h1. DRY SCAFFOLD A Rails scaffold generator that generates DRYer, cleaner, and more useful code. h2. 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. The goal with DryScaffold is to generate DRY, beautiful, and standards compliant code based on common patterns without adding a lot of magic. h4. 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 * 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 h2. Dependencies h3. Required: * "*haml*":http://github.com/nex3/haml - ERB sucks like PHP, end of story h3. Optional: * "*will_paginate*":http://github.com/mislav/will_paginate - Pagination * "*formtastic*":http://github.com/justinfrench/formtastic - DRY and semantic forms * "*inherited_resources*":http://github.com/josevalim/inherited_resources - DRY/Resourceful controllers h2. Features h3. 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. h3. 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. h4. Default HAML (without Formtastic):
- form_for(@<%= singular_name %>) do |f|
  = f.error_messages
  %ul
    %li
      = f.label :title, 'Title'
      = f.text_field :title
    %li
      = f.label :description, 'Description'
      = f.text_field :description
  %p.buttons
    = f.submit 'Create'
h4. Formtastic + HAML:
- semantic_form_for(@resource) do |f|
  - f.inputs do
    = f.input :title
    = f.input :description
  - f.buttons do
    = f.commit_button 'Create'
Find out more about *formtastic*: "http://github.com/justinfrench/formtastic":http://github.com/justinfrench/formtastic h3. 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. h4. Default (without InheritedResources)
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
h4. Resourceful (InheritedResources)
actions :new
respond_to :html, :xml, :json
Find out more about *inherited_resources*: "http://github.com/josevalim/inherited_resources":http://github.com/josevalim/inherited_resources h3. Pagination Pagination is such a common feature that always seems to be implemented anyway, so dry_scaffold 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. Find out more about *will_paginate*: "http://github.com/mislav/will_paginate":http://github.com/mislav/will_paginate h3. DRY 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. h4. Default (ActionController, without InheritedResources)
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
h4. Resourceful (InheritedResources)
protected
  
  def collection
    paginate_options ||= {}
    paginate_options[:page] ||= (params[:page] || 1)
    paginate_options[:per_page] ||= (params[:per_page] || 20)
    @collection = @resources ||= end_of_association_chain.paginate(paginate_options)
  end
  
  def resource
    @resource = @resource ||= end_of_association_chain.find(params[:id])
  end
h3. View Partials A very common pattern is to break up views in partials, wich is also what DryScaffold does: * new/edit => _form * index => _item h3. More To Come... (TODO) These are things I have in mind: * Generation of factory stubs instead of fixture stubs that Rails model generator generates * Generation of Rails builder stubs (RSS/Atom/...) * Break up into multiple generators as dependencies (like Rails generators): dry_controller, dry_views, dry_scaffold, ... h2. Setup Installing DryScaffold is easy as 1-2-3...nah, really: h3. 1. Installation Install DryScaffold... h4. Gem (Recommended)
gem sources -a http://gems.github.com
sudo gem install grimen-dry_scaffold
h4. Plugin
./script/plugin install git://github.com/grimen/dry_scaffold.git
h3. 2. Configuration (Gem only) In: @config/environments/development.rb@
config.gem 'grimen-dry_scaffold', :lib => 'dry_scaffold'
h3. 3. 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? =) h4. Installation, i.e. get the gems
sudo gem install haml
sudo gem install will_paginate
sudo gem install justinfrench-formtastic
sudo gem install josevalim-inherited_resources
h4. Configuration In: @config/environment.rb@
config.gem 'haml'
config.gem 'will_paginate'
config.gem 'justinfrench-formtastic', :lib => 'formtastic, :source => 'http://gems.github.com'
config.gem 'josevalim-inherited_resources', :lib => 'inherited_resources', :source => 'http://gems.github.com'
h2. Usage
./script/generate dry_scaffold ModelName [attribute:type attribute:type] [_actions:new,create,...] [_formats:html,json,...] [--skip-pagination] [--skip-resourceful] [--skip-formtastic] [--skip-views] [--skip-helpers] [--skip-tests] [--include-layout]
h3. Model Name Example:
Hello
Same as in the default scaffold/model generator; the name of a new/existing model. h3. Model Attributes Example:
title:string description:text ...
Same as in the default scaffold/model generator; model attributes and database migration column types. h3. Controller Actions Usage:
_actions:new,create,recent,index,...
You can override what actions that should be generated directly - including custom actions. NOTE: Sorry for the a bit ugly prefix (_), but I had to trick the Rails generator a bit to get this working for now. This is definitely something I want to fix sooner or later, but I skipped that for now with this small hack. h4. 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. h4. 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. h3. Controller Formats Usage:
_formats: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. NOTE: Sorry for the a bit ugly prefix (_), but I had to trick the Rails generator a bit to get this working for now. This is definitely something I want to fix sooner or later, but I skipped that for now with this small hack. h4. Default formats If no formats are specified, the following formats will be generated by default: * @html@ => Render: resource using view template (HTML/HAML) * @js@ => Render: resource using view template (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. h4. Additional formats Also, default respond block stubs are generated for any of these formats - for each generated REST-action - if they are specified: * @yaml@ or @yml@ => Render: resource.to_yaml * @txt@ or @text@ => Render: resource.to_s h4. 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. h3. Options/Flags Example:
--skip-resourceful --include-layout
* @--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-tests@ - Don't generate tests (functional/unit/...). * @--include-layout@ - Generate a neat application layout. As DryScaffold is built upon Rails generator, the default generator options is available as well. For more details; see Rails documentation. h2. Examples No need for more samples here, just create a new Rails project, install dry_scaffold 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 dry_scaffold Kangaroo name:string about:text --skip-formtastic
./script/generate dry_scaffold Duck name:string about:text _actions:new,create,index,quack
./script/generate dry_scaffold Parrot name:string about:text _formats:html,xml,yml
...or just go crazy! h2. 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! Copyright (c) 2009 Jonas Grimfelt