Rails源码研究之ActionController:三,scaffolding

Rails里富有Magic的东西往往实现起来非常简单,比如scaffolding
看看代码先,scaffolding.rb:
module ActionController

  module Scaffolding

    def self.included(base)
      base.extend(ClassMethods)
    end

    module ClassMethods

      def scaffold(model_id, options = {})
        options.assert_valid_keys(:class_name, :suffix)

        singular_name = model_id.to_s
        class_name    = options[:class_name] || singular_name.camelize
        plural_name   = singular_name.pluralize
        suffix        = options[:suffix] ? "_#{singular_name}" : ""

        unless options[:suffix]
          module_eval <<-"end_eval", __FILE__, __LINE__
            def index
              list
            end
          end_eval
        end

        module_eval <<-"end_eval", __FILE__, __LINE__

          verify :method => :post, :only => [ :destroy#{suffix}, :create#{suffix}, :update#{suffix} ],
                 :redirect_to => { :action => :list#{suffix} }

          def list#{suffix}
            @#{singular_name}_pages, @#{plural_name} = paginate :#{plural_name}, :per_page => 10
            render#{suffix}_scaffold "list#{suffix}"
          end

          def show#{suffix}
            @#{singular_name} = #{class_name}.find(params[:id])
            render#{suffix}_scaffold
          end

          def destroy#{suffix}
            #{class_name}.find(params[:id]).destroy
            redirect_to :action => "list#{suffix}"
          end

          def new#{suffix}
            @#{singular_name} = #{class_name}.new
            render#{suffix}_scaffold
          end

          def create#{suffix}
            @#{singular_name} = #{class_name}.new(params[:#{singular_name}])
            if @#{singular_name}.save
              flash[:notice] = "#{class_name} was successfully created"
              redirect_to :action => "list#{suffix}"
            else
              render#{suffix}_scaffold('new')
            end
          end

          def edit#{suffix}
            @#{singular_name} = #{class_name}.find(params[:id])
            render#{suffix}_scaffold
          end

          def update#{suffix}
            @#{singular_name} = #{class_name}.find(params[:id])
            @#{singular_name}.attributes = params[:#{singular_name}]
            if @#{singular_name}.save
              flash[:notice] = "#{class_name} was successfully updated"
              redirect_to :action => "show#{suffix}", :id => @#{singular_name}
            else
              render#{suffix}_scaffold('edit')
            end
          end

          private

            def render#{suffix}_scaffold(action=nil)
              action ||= caller_method_name(caller)
              if template_exists?("\#{self.class.controller_path}/\#{action}")
                render :action => action
              else
                @scaffold_class = #{class_name}
                @scaffold_singular_name, @scaffold_plural_name = "#{singular_name}", "#{plural_name}"
                @scaffold_suffix = "#{suffix}"
                add_instance_variables_to_assigns
                @template.instance_variable_set("@content_for_layout", @template.render_file(scaffold_path(action.sub(/#{suffix}$/, "")), false))
                if !active_layout.nil?
                  render :file => active_layout, :use_full_path => true
                else
                  render :file => scaffold_path('layout')
                end
              end
            end

            def scaffold_path(template_name)
              File.dirname(__FILE__) + "/templates/scaffolds/" + template_name + ".rhtml"
            end

            def caller_method_name(caller)
              caller.first.scan(/`(.*)'/).first.first
            end

        end_eval

      end

    end

  end

end

代码非常清楚,使用module_eval生成list/show/destroy/new/create/edit/update方法,然后调用render#{suffix}_scaffold方法
render#{suffix}_scaffold方法首先判断是否存在调用它的action的模板,如blog/new.rhtml,如果没有则使用scaffold_path下默认的模板new.rhtml

我们可以给scaffold方法给一个参数:suffix => true,这样生成的action方法带__#{singular_name}参数,如list_post、new_post

而默认的scaffold模板就在actionpack-1.13.3\lib\action_controller\templates\scaffolds目录下

你可能感兴趣的:(Blog,Flash,Ruby,Rails)