1 module ActionController
2 module Scaffolding # :nodoc:
3 def self.included(base)
4 base.extend(ClassMethods)
7 # Scaffolding is a way to quickly put an Active Record class online by providing a series of standardized actions
8 # for listing, showing, creating, updating, and destroying objects of the class. These standardized actions come
9 # with both controller logic and default templates that through introspection already know which fields to display
10 # and which input types to use. Example:
12 # class WeblogController < ActionController::Base
16 # This tiny piece of code will add all of the following methods to the controller:
18 # class WeblogController < ActionController::Base
19 # verify :method => :post, :only => [ :destroy, :create, :update ],
20 # :redirect_to => { :action => :list }
27 # @entries = Entry.find(:all)
28 # render_scaffold "list"
32 # @entry = Entry.find(params[:id])
37 # Entry.find(params[:id]).destroy
38 # redirect_to :action => "list"
47 # @entry = Entry.new(params[:entry])
49 # flash[:notice] = "Entry was successfully created"
50 # redirect_to :action => "list"
52 # render_scaffold('new')
57 # @entry = Entry.find(params[:id])
62 # @entry = Entry.find(params[:id])
63 # @entry.attributes = params[:entry]
66 # flash[:notice] = "Entry was successfully updated"
67 # redirect_to :action => "show", :id => @entry
69 # render_scaffold('edit')
74 # The <tt>render_scaffold</tt> method will first check to see if you've made your own template (like "weblog/show.erb" for
75 # the show action) and if not, then render the generic template for that action. This gives you the possibility of using the
76 # scaffold while you're building your specific application. Start out with a totally generic setup, then replace one template
77 # and one action at a time while relying on the rest of the scaffolded templates and actions.
79 # Adds a swath of generic CRUD actions to the controller. The +model_id+ is automatically converted into a class name unless
80 # one is specifically provide through <tt>options[:class_name]</tt>. So <tt>scaffold :post</tt> would use Post as the class
81 # and @post/@posts for the instance variables.
83 # It's possible to use more than one scaffold in a single controller by specifying <tt>options[:suffix] = true</tt>. This will
84 # make <tt>scaffold :post, :suffix => true</tt> use method names like list_post, show_post, and create_post
85 # instead of just list, show, and post. If suffix is used, then no index method is added.
86 def scaffold(model_id, options = {})
87 options.assert_valid_keys(:class_name, :suffix)
89 singular_name = model_id.to_s
90 class_name = options[:class_name] || singular_name.camelize
91 plural_name = singular_name.pluralize
92 suffix = options[:suffix] ? "_#{singular_name}" : ""
94 unless options[:suffix]
95 module_eval <<-"end_eval", __FILE__, __LINE__
102 module_eval <<-"end_eval", __FILE__, __LINE__
104 verify :method => :post, :only => [ :destroy#{suffix}, :create#{suffix}, :update#{suffix} ],
105 :redirect_to => { :action => :list#{suffix} }
109 @#{singular_name}_pages, @#{plural_name} = paginate :#{plural_name}, :per_page => 10
110 render#{suffix}_scaffold "list#{suffix}"
114 @#{singular_name} = #{class_name}.find(params[:id])
115 render#{suffix}_scaffold
119 #{class_name}.find(params[:id]).destroy
120 redirect_to :action => "list#{suffix}"
124 @#{singular_name} = #{class_name}.new
125 render#{suffix}_scaffold
129 @#{singular_name} = #{class_name}.new(params[:#{singular_name}])
130 if @#{singular_name}.save
131 flash[:notice] = "#{class_name} was successfully created"
132 redirect_to :action => "list#{suffix}"
134 render#{suffix}_scaffold('new')
139 @#{singular_name} = #{class_name}.find(params[:id])
140 render#{suffix}_scaffold
144 @#{singular_name} = #{class_name}.find(params[:id])
145 @#{singular_name}.attributes = params[:#{singular_name}]
147 if @#{singular_name}.save
148 flash[:notice] = "#{class_name} was successfully updated"
149 redirect_to :action => "show#{suffix}", :id => @#{singular_name}
151 render#{suffix}_scaffold('edit')
156 def render#{suffix}_scaffold(action=nil)
157 action ||= caller_method_name(caller)
158 # logger.info ("testing template:" + "\#{self.class.controller_path}/\#{action}") if logger
160 if template_exists?("\#{self.class.controller_path}/\#{action}")
161 render :action => action
163 @scaffold_class = #{class_name}
164 @scaffold_singular_name, @scaffold_plural_name = "#{singular_name}", "#{plural_name}"
165 @scaffold_suffix = "#{suffix}"
166 add_instance_variables_to_assigns
168 @template.instance_variable_set("@content_for_layout", @template.render_file(scaffold_path(action.sub(/#{suffix}$/, "")), false))
170 if !active_layout.nil?
171 render :file => active_layout, :use_full_path => true
173 render :file => scaffold_path('layout')
178 def scaffold_path(template_name)
179 File.dirname(__FILE__) + "/templates/scaffolds/" + template_name + ".erb"
182 def caller_method_name(caller)
183 caller.first.scan(/`(.*)'/).first.first # ' ruby-mode
188 deprecate :scaffold => 'Controller scaffolding will be moved to a plugin in Rails 2.0. Switch to the generator or `script/plugin install scaffolding`'