Giter Site home page Giter Site logo

dry_scaffold's Introduction

DRY SCAFFOLD

A Rails scaffold generator that generates DRYer, cleaner, and more useful code.

Description

DryScaffold is a replacement for the Rails scaffold generator that generates code that most people end up deleting or rewriting anyway because of the unusable code. The scaffold concept is powerful, but it has more potential than generating messy and almost useless code – something that might change with Rails 3 though. The goal with DryScaffold is to generate DRY, beautiful, and standards compliant code based on common patterns without adding a lot of assumptions.

Key Concepts:

  • Controllers that are DRY, RESTful, no code-smells, following conventions, and implementing VERY common patterns.
  • Views that are DRY, semantic, standards compliant, valid, and more useful in development.
  • Factories instead of fixtures.
  • Generator that gets smart with additional arguments – but not stupid without them.
  • Any Rails developer should be able to switch generator with no effort – follow current conventions, but extend them.

Dependencies

Required:

  • hamlERB sucks like PHP, end of story

Optional:

Controllers/Views

Models

Testing

Features

Overview

The most characteristic features:

  • Generates DRY controllers + functional tests.
  • Generates DRY, semantic, and standard compliant views in HAML – not just HAMLized templates.
  • Generates formtastic – very DRY – forms (using “formtastic” by Justin French et. al.) by default. Note: Can be turned off.
  • Generates resourceful – even DRYer – controllers (using the “inherited_resources” by José Valim) by default. Note: Can be turned off.
  • Collection pagination using will_paginate by default. Note: Can be turned off.
  • Optionally specify what actions/views to generate (stubs for specified REST-actions will be generated).
  • Optionally specify what respond_to-formats to generate (stubs for the most common respond_to-formats will be generated).
  • Generates default helpers/models/migrations, and REST-routes (if not already defined).
  • Override default templates with app-specific ones without hassle.

Formtastic Forms

Quick and dirty; Formtastic makes your form views cleaner, and your life as a Rails developer easier (for real). Formtastic forms can be turned off, but I would recommend any Rails developer to consider using it – there is really no good reason not to if you not running very old version of Rails.

Standard

HAML + ActionView FormHelpers:

- form_for(@duck) do |f|
  = f.error_messages
  %ul
    %li
      = f.label :name, 'Name'
      = f.text_field :name
    %li
      = f.label :about, 'About'
      = f.text_area :about
  %p.buttons
    = f.submit 'Create'

Formtastic

HAML + Formtastic:

- semantic_form_for(@duck) do |f|
  - f.inputs do
    = f.input :name
    = f.input :about
  - f.buttons do
    = f.commit_button 'Create'

Find out more about formtastic: http://github.com/justinfrench/formtastic

Resourceful Controllers

Quick and dirty; InheritedResources makes your controllers controllers cleaner, and might make experienced Rails developer’s life DRYer code wise. This is possible because of REST as a convention in Rails, and therefore the patterns that arise in controllers can be DRYed up A LOT. Resourceful – InheritedResources-based – controllers can be turned off, but I would recommend any experienced Rails developer to consider using it – there is really no good reason not to unless maybe if you are a Rails beginner, then you should consider get used to the basic Rails building blocks first.

Standard

Using ActionController:

def new
  @duck = Duck.new
  
  respond_to do |format|
    format.html # new.html.haml
    format.xml  { render :xml => @duck }
    format.json { render :json => @duck }
  end
end

Resourceful

Using InheritedResources:

actions :new
respond_to :html, :xml, :json

Find out more about inherited_resources: http://github.com/josevalim/inherited_resources

Pagination

Pagination is such a common feature that always seems to be implemented anyway, so DryScaffold will generate a DRY solution for this in each controller that you can tweak – even thought that will not be needed in most cases. See DRY Patterns beneath for more details how it’s done. Pagination – using WillPaginate – can be turned off.

Find out more about will_paginate: http://github.com/mislav/will_paginate

DRYying Patterns

Either if you choosing default or resourceful controllers, this pattern is used to DRYing up controllers a bit more, and at the same time loading resources in the same place using before_filter while adding automatic pagination for collections.

Standard

ActionController with pagination:

before_filter :load_resource, :only => [:show, :edit, :update, :destroy]
before_filter :load_and_paginate_resources, :only => [:index]

...

protected
  
  def collection
    paginate_options ||= {}
    paginate_options[:page] ||= (params[:page] || 1)
    paginate_options[:per_page] ||= (params[:per_page] || 20)
    @collection = @resources ||= Duck.paginate(paginate_options)
  end
  alias :load_and_paginate_resources :collection
  
  def resource
    @resource = @resource = ||= Duck.find(params[:id])
  end
  alias :load_resource :resource

Resourceful

InheritedResources with pagination:

protected
  
  def collection
    paginate_options ||= {}
    paginate_options[:page] ||= (params[:page] || 1)
    paginate_options[:per_page] ||= (params[:per_page] || 20)
    @resources ||= end_of_association_chain.paginate(paginate_options)
  end

View Partials

A very common pattern is to break up views in partials, which is also what DryScaffold does:

  • new/edit => _form
  • index => _item

Setup

Installing DryScaffold is easy:

1. Installation

Install DryScaffold…

Gem (Recommended)

sudo gem install dry_scaffold

…and in config: config/environments/development.rb

config.gem 'dry_scaffold', :lib => false

Plugin

./script/plugin install git://github.com/grimen/dry_scaffold.git

2. Install Dependencies (Partly optional)

Install dependencies to release the full power of dry_scaffold. Only HAML is really required of these, but how could anyone resist candy? =)

Automatic/Express

For us lazy ones… =) Note: Probably won’t work without require the rake tasks first in the project Rakefile: require 'dry_scaffold/tasks'

rake dry_scaffold:setup

Will install the dependencies, initialize HAML within current Rails project if not already done, and automatically referencing the dependency gems within the current Rails project environment config if they are not already in there (note: nothing will be overwritten).

Manual

Get the gems…you want:

sudo gem install haml
sudo gem install will_paginate
sudo gem install formtastic
sudo gem install inherited_resources

…and same for the config config: config/environments/development.rb

config.gem 'haml'
config.gem 'will_paginate'
config.gem 'formtastic'
config.gem 'inherited_resources'

Also configure config/environments/test.rb with the RSpec library if you want to

config.gem 'rspec'
config.gem 'rspec-rails'

And don’t forget to initialize it as well:

./script/generate rspec

To access Rake tasks in Rails from the gem version of DryScaffold you need to do this:

In your project Rakefile:

require 'dry_scaffold/tasks'

Don’t ask me why me why this is the only way with gems…Ask the Rails core team, because this is not conventions over configuration. Raur…

Usage

./script/generate dry_scaffold ModelName [attribute:type attribute:type] [_actions:new,create,...] [_formats:html,json,...] [_indexes:attribute,...] [--skip-pagination] [--skip-resourceful] [--skip-formtastic] [--skip-views] [--skip-helpers] [--skip-migration] [--skip-timestamps] [--skip-tests] [--skip-controller-tests] [--layout] [--tunit] [--shoulda] [--rspec] [--fixtures] [--fgirl] [--machinist] [--odaddy]

…or use the alias dscaffold instead of dry_scaffold.

For generating just a model, then use:

./script/generate dry_model ModelName [attribute:type attribute:type] [_indexes:attribute,...] [--skip-migration] [--skip-timestamps] [--skip-tests] [--tunit] [--shoulda] [--rspec] [--fixtures] [--fgirl] [--machinist] [--odaddy]

…or use the alias dmodel instead of dry_model.

Model Name

Example:

Duck

Same as in the default scaffold/model generator; the name of a new/existing model.

Model Attributes

Example:

name:string about:text ...

Same as in the default scaffold/model generator; model attributes and database migration column types.

Controller Actions

Example:

_actions:new,create,quack,index,...

You can override what actions that should be generated directly – including custom actions.

Default Actions (REST)

If no actions are specified, the following REST-actions will be generated by default:

  • show
  • index
  • new
  • edit
  • create
  • update
  • destroy

Default controller action stubs, controller action test stubs, and corresponding views (and required partials), are generated for all of these actions.

These default actions can also be included using the quantifiers * and +, which makes it easier to add new actions without having to specify all the default actions explicit. Example:

_actions:quack               # => quack
_actions:*,quack             # => show,index,new,edit,create,update,destroy,quack
_actions:new+,edit,quack     # => new,edit,create,quack
_actions:new+,edit+,quack    # => new,edit,create,update,quack

Custom Actions

The above REST actions are in many RESTful applications the only ones needed. Any other specified actions will generate empty action function stubs for manual implementation. No views will be generated for custom actions.

Controller Formats

Example:

_formats:html,xml,txt,...   # <=> _respond_to:html,xml,txt,...

You can override what respond_to-formats that should be generated directly – only for REST-actions right now because I tried to avoid bad assumptions.

Default Formats

If no formats are specified, the following formats will be generated by default:

  • html => Template: resource.html.haml
  • js => Template: resource.js.rjs
  • xml => Render: resource.to_xml
  • json => Render: resource.to_json

Default respond block stubs are generated for all of these formats – for each generated REST-action.

Like for actions, these default respond_to-formats can also be included using the alias symbol *, which makes it easier to add new formats without having to specify all the default formats explicit. Example:

_formats:iphone     # => _formats:iphone
_formats:*,iphone   # => _formats:html,js,xml,json,iphone

Additional Formats

Also, default respond block stubs are generated for any of these formats – for each generated REST-action – if they are specified:

  • atom => Template: index.atom.builder
  • rss => Template: index.rss.builder
  • yaml/yml => Render: resource.to_yaml
  • txt/text => Render: resource.to_s

NOTE: Only for Non-InheritedResources controllers for now.

For the feed formats atom and rss, builders are automatically generated if index-action is specified. Example:

app/views/ducks/index.atom.builder

  atom_feed(:language => I18n.locale) do |feed|
    feed.title 'Resources'
    feed.subtitle 'Index of all resources.'
    feed.updated (@resources.first.created_at rescue Time.now.utc).strftime('%Y-%m-%dT%H:%M:%SZ'))
    
    @resources.each do |resource|
      feed.entry(resource) do |entry|
        entry.title 'title'
        entry.summary 'summary'
        
        resource.author do |author|
          author.name 'author_name'
        end
      end
    end
  end

Builder generation can be skipped by specifying the --skip-builders flag.

Custom Formats

The above formats are the most commonly used ones, and respond blocks are already implemented using Rails default dependencies. Any other specified formats (such as PDF, CSV, etc.) will generate empty respond block stubs for manual implementation with help of additional dependencies.

Model Indexes

Example:

If model attributes are specified as:

name:string owner:reference

…then we could do this (for polymorphic association):

_indexes:owner_id                 # => (In migration:) add_index :duck, :owner_id

…or in account for a polymorphic association:

_indexes:owner_id+owner_type      # => (In migration:) add_index :duck, [:owner_id, :owner_type]

NOTE: Of course…you need to specify indexes based on attributes that exists for this model, otherwise your migration will not be valid – DryScaffold is leaving this responsible to you.

Options/Flags

Example:

--skip-resourceful --layout

Scaffold

These are the options for the scaffold-generator.

  • --skip-pagination – Don’t generate pagination of collections in controller and views, i.e. don’t use will_paginate.
  • --skip-resourceful – Don’t generate resourceful controller, i.e. don’t use inherited_resources.
  • --skip-formtastic – Don’t generate formtastic forms in views, i.e. don’t use formtastic.
  • --skip-views – Don’t generate views.
  • --skip-helpers – Don’t generate helpers.
  • --skip-builders – Don’t generate builders.
  • --skip-controller-tests – Don’t generate controller tests
  • --layout – Generate layout.

Model

These are the options for the model/scaffold-generators.

  • --skip-timestamps – Don’t add timestamps to the migration file.
  • --skip-migration – Skip generation of migration file.

All

  • --skip-tests – Don’t generate tests (functional/unit/…).
  • --tunit – Generate/Use test_unit tests. Note: Rails default.
  • --shoulda – Generate/Use shoulda tests.
  • --rspec – Generate/Use rspec tests.
  • --fixtures – Generate/Use fixtures. Note: Rails default.
  • --fgirl – Generate/Use factory_girl factories.
  • --machinist – Generate/Use machinist blueprints (factories).
  • --odaddy – Generate/Use object_daddy generator/factory methods.

As DryScaffold is built upon Rails generator, the default generator options is available as well. For more details; see Rails documentation.

Setting Defaults

You can set defaults for the generator args/options in config/scaffold.yml. To generate this file, simply do:

rake dry_scaffold:config:generate

Overriding default templates

You can very easily override the default DryScaffold templates (views, controllers, whatever…) by creating custom template files according to the same relative path as the generator templates in RAILS_ROOT/lib/scaffold_templates.

Example: Override the index view template

In DryScaffold the index template file is located in:

GEM_ROOT/generators/dry_scaffold/templates/views/haml/index.html.haml

…which means that if you want to override it, you should have your custom template in:

RAILS_ROOT/lib/scaffold_templates/views/haml/index.html.haml

Copying template files to this location for overriding needs to be done manually for now, but maybe there will be a generator for this later on. That would be useful at least. =)

Examples

No need for more samples here, just create a new Rails project, install DryScaffold and it’s dependencies, and try it out!

For your inspiration, you could try the following:

./script/generate dry_scaffold Zebra name:string about:text --skip-resourceful
./script/generate dscaffold Kangaroo name:string about:text --skip-formtastic
./script/generate dscaffold Duck name:string about:text _actions:new,create,index,quack
./script/generate dscaffold Parrot name:string about:text _formats:html,xml,yml
./script/generate dmodel GoldFish name:string about:text _indexes:name --fgirl
./script/generate dmodel Frog name:string about:text _indexes:name,name+about --fixtures

…or just go crazy!

Bugs & Feedback

If you experience any issues/bugs or have feature requests, just file a GitHub-issue or send me a message.
If you think parts of my implementation could be implemented nicer somehow, please let me know…or just fork it and fix it yourself! =)
At last, positive feedback is always appreciated!

License

Copyright © 2009 Jonas Grimfelt, released under the MIT-license.

dry_scaffold's People

Contributors

akitaonrails avatar grimen avatar pelle avatar semarco avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

dry_scaffold's Issues

InheritedResorces testing issue

Contact José regarding the InheritedResources-issue:

  1. ActionController::RoutingError: parrot_url failed to generate from {:controller=>"parrots", :id=>#<Parrot id: nil, name: "Hello", created_at: "2009-07-21 18:53:25", updated_at: "2009-07-21 18:53:25">, :action=>"show"}, expected: {:controller=>"parrots", :action=>"show"}, diff: {:id=>#<Parrot id: nil, name: "Hello", created_at: "2009-07-21 18:53:25", updated_at: "2009-07-21 18:53:25">}
    (eval):16:in parrot_url' /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/url_helpers.rb:194:inresource_url'
    /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base_helpers.rb:311:in send' /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base_helpers.rb:311:inparse_redirect_url'
    /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base.rb:79:in create' /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/respond_to.rb:301:incall'
    /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/respond_to.rb:301:in respond_any' /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/respond_to.rb:233:inrespond_to'
    /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base_helpers.rb:283:in respond_to_with_dual_blocks' /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base.rb:78:increate'
    haml (2.0.9) rails/./lib/sass/plugin/rails.rb:19:in process' /test/functional/donkeys_controller_test.rb:8:intest_create'

test 'create' do
Donkey.any_instance.expects(:save).returns(true)
@donkey = donkeys(:basic)
post :create, :donkey => @donkey.attributes # <<<<<<<<<<<<< donkeys_controller_test.rb:8
assert_response :redirect
end

  1. test_destroy_with_failure(DonkeysControllerTest) [/test/functional/donkeys_controller_test.rb:45]:
    expected to not be nil.

test 'destroy with failure' do
Donkey.any_instance.expects(:destroy).returns(false)
@donkey = donkeys(:basic)
delete :destroy, :id => @donkey.to_param
assert_not_nil flash[:error] # <<<<<<<<<<<<< donkeys_controller_test.rb:45
assert_response :redirect
end

build_object reads wrong option

build_object reads 'factory_framework' but it is not set in scaffold.yml. in the yaml file, some other options are set 'true/false'

Factories only created sporadically

I generated 3 scaffolds and 2 models on the command line, specifying --fgirl for each one, yet a Factory was only generated for one of the five.

fgirl option in config file

Setting 'fgirl' option to true in a config does not seem to work. Looking at code option should probably be 'factory_girl' but setting that to true does not work as expected either.

@resource and @collection throw errors in views

Right now the following order generates errors (with all the dependencies installed):
./script/generate dscaffold Duck name:string about:text _actions:new,create,index,quack

The errors are:

  1. On apps/views/duck/index.html.haml
    @collection.each do |resource| #gives an error (@collection is nil)
  2. On apps/views/duck/new.html.haml
    semantic_form_for(@resource) do |form| #gives an error (@resource is nil)

I believe the second error will also happen on edit - I just didn't generate a view for the action.

If I change @collection and @resource to @ducks and @duck the errors go away.

RSpec-support

Add option to generate RSpec-tests instead of Test::Unit/Shoulda.

i18n of table & page headings, attribute names, links and buttons

The following command:
./script/generate dscaffold Duck name:string about:text _actions:new,create,index,quack

Will generate the following in app/views/duck/index.html.haml

= "Resources" # I believe this was meant to say "Ducks"?
...
%th.name= 'Name'
%th.about= 'About'
%th.actions= 'Actions'

This makes i18n generation difficult. I suggest ussing human_name & human_attribute_name for the header & attributes, and t('Actions) for the Action header:
= Duck.human_name(:count => 2)
...
%th.name= Duck.human_attribute_name(:name)
%th.about= Duck.human_attribute_name(:about)
%th.actions= t('Actions')

Similarly, the links & buttons can be made i18n-compliant quite easily. The following lines:
= form.commit_button 'Create'
= link_to 'Show', resource_path(resource)
= will_paginate(@collection)
would become:
= form.commit_button t('Create')
= link_to t('Show'), resource_path(resource)
= will_paginate(@collection, :previous_label => t('Previous'), :next_label => t('Next') )

dscaffold can't find default configuration file

Generator fails for some reason:

$ dscaffold ...
No such file or directory - /opt/local/lib/ruby/gems/1.8/gems/grimen-dry_scaffold-0.2.3/generators/dscaffold/../dry_scaffold/../../config/scaffold.yml

Generate links for actions in _actions only

This action:
./script/generate dscaffold Duck name:string about:text _actions:new,create,index,quack

Generates "edit" links on the _item view.

Of course, if _actions isn't specified, it can be assumed that the default _actions are set.

Use inherited_resources paths

Use collection_path, resource_path, etc. unless skipping inherited_resources.
Also, perhaps use the longer method for creating the form tag...

- semantic_form_for resource, :url => edit_resource_path(resource) do |form|

This will allow belongs_to/polymorphic controllers without any updates to the views.

README-typo

Should be:

config.gem 'grimen-dry_scaffold', :lib => false

undefined method `total_pages'

When I generate a dry_scaffold, run the migration, and go to the index page, I received the error

undefined method `total_pages'

Why does this happen?

--skip-resourceful doesn't

After experiencing some issues with the inherited_resources bits I decided to just skip them for now. But when I run "script/generate dry_scaffold Zebra name:string about:text --skip-resourceful" in my project the resourceful controller and views are still created.

:Fuzz

rais3

Hi!

This is a wonderful asset when creating apps and I use it al of the time. Curious, is there a Rails3 branch for this gem?

I know that Rails3 provides a new way of doing generators and templates where you could create something like this pretty easily. I do like the way you currently do it with dry_scaffold.

Thanks in advance,
Mark

Does not create route

When generating a new scaffold the routes are not updated. I don't know if this is the intentional behaviour or not...

Generating a dry_scaffold with versions 0.3.6 or 0.3.7 you get a non working scaffold!

Hi,

the generated scaffolds seem to be broken.

When generating a dry_scaffold wrong variable names are rendered in the views (using the default options).

Example:
ruby script/generate dry_scaffold Book ...

In index.html.haml the collection variable is referenced as @collection where it should be @books (as defined in the corresponding controller).

In new.html.haml, edit.html.haml and show.html.haml the instance variable is referenced as @resource where it should be @book

The titles in the views are also generated wrong: "New resource" "Editing resource..." etc. instead of "New book", etc. etc.

dry_scaffold not working (Can't convert nil to String)

The command I'm running is the line below. The line immediately following is the only response I get from the attempt. This is on an established project that has no other (apparent) issues.

generate dry_scaffold User name:string email:string
can't convert nil into String

I'm running Rails 2.3.5.

config/scaffold.yml doesn't seem to be honoring...

my:

resourceful: false
shoulda: true

I've done this a couple times today to make sure - here's a gist:

http://gist.github.com/224563

If I pass it on the command line - it works just fine:

./script/generate dry_scaffold Zebra name:string about:text --skip-resourceful --shoulda

I may be doing something wrong - but I just want to:

create a rails app
add dry_scaffold
add a simple model/controller with your scaffold generator
have the basic tests pass

And I can't seem to be able to do that - like I said, I may be doing something wrong, but am not sure what.

Option toggling

Come up with a smooth way to disable an option that is true by default, i.e. negative toggle.

"Best practices" tests

Write even better functional tests for REST-actions. Goal: Killer-tests, i.e. "best practice"-tests. Suggestion: Routing, formats, ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.