`
hideto
  • 浏览: 2678430 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

每天一剂Rails良药之scaffolding

    博客分类:
  • Ruby
阅读更多
对于如下代码:
class WeblogController < ActionController::Base
  scaffold :entry
end

这将生成如下代码:
class WeblogController < ActionController::Base

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

  def index
    list
  end

  def list
    @entries = Entry.find(:all)
    render_scaffold "list"
  end

  def show
    @entry = Entry.find(params[:id])
    render_scaffold
  end

  def destroy
    Entry.find(params[:id]).destroy
    redirect_to :action => "list"
  end

  def new
    @entry = Entry.new
    render_scaffold
  end

  def create
    @entry = Entry.new(params[:entry])
    if @entry.save
      flash[:notice] = "Entry was successfully created"
      redirect_to :action => "list"
    else
      render_scaffold('new')
    end
  end

  def edit
    @entry = Entry.find(params[:id])
    render_scaffold
  end

  def update
    @entry = Entry.find(params[:id])
    @entry.attributes = params[:entry]
    if @entry.save
      flash[:notice] = "Entry was successfully updated"
      redirect_to :action => "show", :id => @entry
    else
      render_scaffold('edit')
    end
  end

end


原来scaffolding是一个Rails的插件,源码如下:
module Scaffolding # :nodoc:
  def self.included(base)
    base.extend(ClassMethods)
  end

  # Scaffolding is a way to quickly put an Active Record class online by providing a series of standardized actions
  # for listing, showing, creating, updating, and destroying objects of the class. These standardized actions come
  # with both controller logic and default templates that through introspection already know which fields to display
  # and which input types to use. Example:
  #
  #  class WeblogController < ActionController::Base
  #    scaffold :entry
  #  end
  #
  # This tiny piece of code will add all of the following methods to the controller:
  #
  #  class WeblogController < ActionController::Base
  #    verify :method => :post, \:only => [ :destroy, :create, :update ],
  #           :redirect_to => { :action => :list }
  #
  #    def index
  #      list
  #    end
  #
  #    def list
  #      @entries = Entry.find(:all)
  #      render_scaffold "list"
  #    end
  #
  #    def show
  #      @entry = Entry.find(params[:id])
  #      render_scaffold
  #    end
  #
  #    def destroy
  #      Entry.find(params[:id]).destroy
  #      redirect_to :action => "list"
  #    end
  #
  #    def new
  #      @entry = Entry.new
  #      render_scaffold
  #    end
  #
  #    def create
  #      @entry = Entry.new(params[:entry])
  #      if @entry.save
  #        flash[:notice] = "Entry was successfully created"
  #        redirect_to :action => "list"
  #      else
  #        render_scaffold('new')
  #      end
  #    end
  #
  #    def edit
  #      @entry = Entry.find(params[:id])
  #      render_scaffold
  #    end
  #
  #    def update
  #      @entry = Entry.find(params[:id])
  #      @entry.attributes = params[:entry]
  #
  #      if @entry.save
  #        flash[:notice] = "Entry was successfully updated"
  #        redirect_to :action => "show", :id => @entry
  #      else
  #        render_scaffold('edit')
  #      end
  #    end
  #  end
  #
  # The <tt>render_scaffold</tt> method will first check to see if you've made your own template (like "weblog/show.erb" for
  # the show action) and if not, then render the generic template for that action. This gives you the possibility of using the
  # scaffold while you're building your specific application. Start out with a totally generic setup, then replace one template
  # and one action at a time while relying on the rest of the scaffolded templates and actions.
  module ClassMethods
    # Adds a swath of generic CRUD actions to the controller. The +model_id+ is automatically converted into a class name unless
    # one is specifically provide through <tt>options[:class_name]</tt>. So <tt>scaffold :post</tt> would use Post as the class
    # and @post/@posts for the instance variables.
    #
    # It's possible to use more than one scaffold in a single controller by specifying <tt>options[:suffix] = true</tt>. This will
    # make <tt>scaffold :post, :suffix => true</tt> use method names like list_post, show_post, and create_post
    # instead of just list, show, and post. If suffix is used, then no index method is added.
    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)
            # logger.info ("testing template:" + "\#{self.class.controller_path}/\#{action}") if logger

            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/" + template_name + ".erb"
          end

          def caller_method_name(caller)
            caller.first.scan(/`(.*)'/).first.first # ' ruby-mode
          end
      end_eval
    end
  end
end


现在的scaffolding源码在$RUBY_HOME\lib\ruby\gems\1.8\gems\actionpack-1.13.3\lib\action_controller\scaffolding.rb:
module ActionController
  module Scaffolding # :nodoc:
    def self.included(base)
      base.extend(ClassMethods)
    end

    # Scaffolding is a way to quickly put an Active Record class online by providing a series of standardized actions
    # for listing, showing, creating, updating, and destroying objects of the class. These standardized actions come
    # with both controller logic and default templates that through introspection already know which fields to display
    # and which input types to use. Example:
    #
    #  class WeblogController < ActionController::Base
    #    scaffold :entry
    #  end
    #
    # This tiny piece of code will add all of the following methods to the controller:
    #
    #  class WeblogController < ActionController::Base
    #    verify :method => :post, \:only => [ :destroy, :create, :update ],
    #           :redirect_to => { :action => :list }
    #
    #    def index
    #      list
    #    end
    #
    #    def list
    #      @entries = Entry.find(:all)
    #      render_scaffold "list"
    #    end
    #
    #    def show
    #      @entry = Entry.find(params[:id])
    #      render_scaffold
    #    end
    #
    #    def destroy
    #      Entry.find(params[:id]).destroy
    #      redirect_to :action => "list"
    #    end
    #
    #    def new
    #      @entry = Entry.new
    #      render_scaffold
    #    end
    #
    #    def create
    #      @entry = Entry.new(params[:entry])
    #      if @entry.save
    #        flash[:notice] = "Entry was successfully created"
    #        redirect_to :action => "list"
    #      else
    #        render_scaffold('new')
    #      end
    #    end
    #
    #    def edit
    #      @entry = Entry.find(params[:id])
    #      render_scaffold
    #    end
    #
    #    def update
    #      @entry = Entry.find(params[:id])
    #      @entry.attributes = params[:entry]
    #
    #      if @entry.save
    #        flash[:notice] = "Entry was successfully updated"
    #        redirect_to :action => "show", :id => @entry
    #      else
    #        render_scaffold('edit')
    #      end
    #    end
    #  end
    #
    # The <tt>render_scaffold</tt> method will first check to see if you've made your own template (like "weblog/show.rhtml" for
    # the show action) and if not, then render the generic template for that action. This gives you the possibility of using the
    # scaffold while you're building your specific application. Start out with a totally generic setup, then replace one template
    # and one action at a time while relying on the rest of the scaffolded templates and actions.
    module ClassMethods
      # Adds a swath of generic CRUD actions to the controller. The +model_id+ is automatically converted into a class name unless
      # one is specifically provide through <tt>options[:class_name]</tt>. So <tt>scaffold :post</tt> would use Post as the class
      # and @post/@posts for the instance variables.
      #
      # It's possible to use more than one scaffold in a single controller by specifying <tt>options[:suffix] = true</tt>. This will
      # make <tt>scaffold :post, :suffix => true</tt> use method names like list_post, show_post, and create_post
      # instead of just list, show, and post. If suffix is used, then no index method is added.
      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)
              # logger.info ("testing template:" + "\#{self.class.controller_path}/\#{action}") if logger

              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 # ' ruby-mode
            end
        end_eval
      end
    end
  end
end

其中module_eval的方式很不错
分享到:
评论

相关推荐

    rails2.3.2

    Rails 作为 Ruby 的主要应用框架之一,两者密切相关。 在压缩包的文件名称列表中,只有一个条目 "rails",这可能意味着压缩包内包含了 Rails 框架的核心文件,如 gemspec 文件、库文件、初始化脚本等。开发者可以...

    Rails 101 入门电子书

    《Rails 101 入门电子书》是一本非常适合初学者直接入门的书籍,它由xdite编写并出版于2014年6月10日。本书主要针对的是希望学习Ruby on Rails框架的读者,特别是那些想要从零开始掌握这项技术的新手。 #### 二、...

    rails指南 中文版

    Rails指南中文版是针对Ruby on Rails框架的一份详尽教程,旨在帮助开发者深入理解并熟练掌握这个强大的Web应用开发工具。Ruby on Rails(简称Rails)是一个基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-...

    rails学习教程

    Rails的scaffolding功能能快速生成一个基本的CRUD(创建、读取、更新、删除)应用界面,是快速原型开发的好帮手。 九、Rails的安全性 Rails提供了许多安全特性,如CSRF防护、XSS防护和参数过滤。了解这些安全措施并...

    Rails101_by_rails4.0

    《Rails101_by_rails4.0》是一本专注于Rails 4.0.0版本和Ruby 2.0.0版本的自学教程书籍,它定位于中文读者,旨在成为学习Rails框架的参考教材。Rails(Ruby on Rails)是一个采用Ruby语言编写的开源Web应用框架,它...

    HeadFirst系列之:深入浅出Rails(中文版)高清完整PDF

    你将学习一切Rails scaffolding的基本原理,以创建自定义的交互式网络应用程序,全部使用Rails的一套丰富的工具和MVC框架。 你将掌握数据库交互、Ajax和XML的集成、丰富的内容,甚至数据的动态图形——曾经要使用...

    rails 项目起步示例

    Rails是Ruby语言的一个著名Web开发框架,全称为Ruby on Rails,它遵循MVC(Model-View-Controller)架构模式,旨在提高开发效率和代码可读性。本示例"rails项目起步示例"是一个购物系统,非常适合初学者入门学习。 ...

    Rails之道.pdf(最新版)

    《Rails之道》详细讨论了Rails的程序代码并通过分析Rails中的代码片段来深入解释它的功能,同时,《Rails之道》部分章节也摘录了一些API文档中的内容,使读者能够快速地找到对应的API文档、相关的示例代码以及深入的...

    Rails项目源代码

    Ruby on Rails,通常简称为Rails,是一个基于Ruby编程语言的开源Web应用框架,遵循MVC(Model-View-Controller)架构模式。这个“Rails项目源代码”是一个使用Rails构建的图片分享网站的完整源代码,它揭示了如何...

    关于rails 3.1 cucumber-rails 1.2.0

    首先,Rails 3.1是Ruby on Rails框架的一个版本,它在2011年发布。这个版本引入了一些显著的改进,如Asset Pipeline(资产管道)和CoffeeScript支持。Asset Pipeline允许开发者更有效地管理和优化应用程序的前端资源...

    rails2-sample

    MVC是Rails的核心架构之一,这一章节将详细介绍这三个组件的作用和相互关系。模型负责与数据库交互,管理数据;视图用于展示数据给用户;控制器则处理用户请求,协调模型和视图之间的操作。了解并正确运用MVC模式是...

    ruby on rails api

    1. **ActiveRecord**:这是Rails的核心组件之一,负责数据库交互。它实现了对象关系映射(ORM),将数据库表映射为Ruby类,使得开发者可以像操作普通对象一样操作数据库记录。 2. **ActionController**:处理HTTP...

    Ruby on Rails Tutorial Learn Rails by Example 的源代码

    10. **Scaffolding**:在`sample_app`中,你可能会看到一些由`rails generate scaffold`命令自动生成的代码,这是一种快速构建基本CRUD(创建、读取、更新、删除)功能的方法。 11. **安全**:`sample_app`可能包含...

    Rails之道.pdf 高清 带书签

    Rails之道.pdf 高清 带书签

    Ruby-Rails实战之B2C商城开发

    在本项目"Ruby-Rails实战之B2C商城开发"中,我们将深入探索使用Ruby on Rails这一强大的Web开发框架来构建一个完整的B2C(Business-to-Consumer)在线商城。Rails是Ruby语言的一个核心框架,以其MVC(Model-View-...

    Rails

    标题 "Rails" 指的是 Ruby on Rails,一个开源的Web应用程序框架,它基于Ruby编程语言,遵循MVC(模型-视图-控制器)架构模式。Rails由David Heinemeier Hansson在2004年创建,其设计理念是强调代码的简洁性、DRY...

    ruby on rails(开发文档)

    Ruby on Rails,简称Rails,是一种基于Ruby语言的开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,极大地简化了Web应用的开发过程。Rails的哲学是“约定优于配置”,鼓励开发者遵循一套标准的...

    Web开发敏捷之道--应用Rails进行敏捷Web开发 之 Depot代码。

    标题中的“Web开发敏捷之道--应用Rails进行敏捷Web开发 之 Depot代码”表明这是一个关于使用Ruby on Rails框架进行敏捷Web开发的示例项目,名为Depot。Ruby on Rails(简称Rails)是一个开源的Web应用程序框架,它...

Global site tag (gtag.js) - Google Analytics