Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #7700: scaffolding_plugin.diff

File scaffolding_plugin.diff, 18.6 kB (added by josh, 2 years ago)
  • plugins/scaffolding/test/scaffolding_test.rb

    old new  
     1require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb')) 
     2require 'action_controller/test_process' 
     3require 'active_record/fixtures' 
     4 
     5ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:") 
     6 
     7ActiveRecord::Schema.define(:version => 1) do 
     8  create_table :entries do |t| 
     9    t.column :title,      :string 
     10    t.column :body,       :text 
     11    t.column :created_at, :datetime 
     12    t.column :updated_at, :datetime 
     13  end 
     14end 
     15 
     16class Entry < ActiveRecord::Base 
     17end 
     18 
     19class WeblogController < ActionController::Base 
     20   scaffold :entry 
     21end 
     22 
     23class ScaffoldingTest < Test::Unit::TestCase 
     24  def setup 
     25    @controller = WeblogController.new 
     26    @request    = ActionController::TestRequest.new 
     27    @response   = ActionController::TestResponse.new 
     28 
     29    @first = Entry.create :title => "Welcome to the weblog", :body => "Such a lovely day" 
     30  end 
     31 
     32  def test_should_get_index 
     33    get :index 
     34    assert_response :success 
     35  end 
     36 
     37  def test_should_get_list 
     38    get :list 
     39    assert_response :success 
     40    assert assigns(:entries) 
     41  end 
     42 
     43  def test_should_show_entry 
     44    get :show, :id => @first.id 
     45    assert_response :success 
     46  end 
     47 
     48  def test_should_get_new 
     49    get :new 
     50    assert_response :success 
     51  end 
     52 
     53  def test_should_create_entry 
     54    old_count = Entry.count 
     55    post :create, :entry => { } 
     56    assert_equal old_count+1, Entry.count 
     57 
     58    assert_redirected_to :action => 'list' 
     59  end 
     60 
     61  def test_should_get_edit 
     62    get :edit, :id => @first.id 
     63    assert_response :success 
     64  end 
     65 
     66  def test_should_update_entry 
     67    post :update, :id => @first.id 
     68    assert_redirected_to :action => 'show', :id => @first.id 
     69  end 
     70 
     71  def test_should_destroy_entry 
     72    old_count = Entry.count 
     73    post :destroy, :id => @first.id 
     74    assert_equal old_count-1, Entry.count 
     75 
     76    assert_redirected_to :action => 'list' 
     77  end 
     78end 
  • plugins/scaffolding/Rakefile

    old new  
     1require 'rake' 
     2require 'rake/testtask' 
     3require 'rake/rdoctask' 
     4 
     5desc 'Default: run unit tests.' 
     6task :default => :test 
     7 
     8desc 'Test the scaffolding plugin.' 
     9Rake::TestTask.new(:test) do |t| 
     10  t.libs << 'lib' 
     11  t.pattern = 'test/**/*_test.rb' 
     12  t.verbose = true 
     13end 
     14 
     15desc 'Generate documentation for the scaffolding plugin.' 
     16Rake::RDocTask.new(:rdoc) do |rdoc| 
     17  rdoc.rdoc_dir = 'rdoc' 
     18  rdoc.title    = 'Scaffolding' 
     19  rdoc.options << '--line-numbers' << '--inline-source' 
     20  rdoc.rdoc_files.include('README') 
     21  rdoc.rdoc_files.include('lib/**/*.rb') 
     22end 
  • plugins/scaffolding/init.rb

    old new  
  • plugins/scaffolding/lib/scaffolding.rb

    old new  
     1module Scaffolding # :nodoc: 
     2  def self.included(base) 
     3    base.extend(ClassMethods) 
     4  end 
     5 
     6  # Scaffolding is a way to quickly put an Active Record class online by providing a series of standardized actions 
     7  # for listing, showing, creating, updating, and destroying objects of the class. These standardized actions come 
     8  # with both controller logic and default templates that through introspection already know which fields to display 
     9  # and which input types to use. Example: 
     10  # 
     11  #  class WeblogController < ActionController::Base 
     12  #    scaffold :entry 
     13  #  end 
     14  # 
     15  # This tiny piece of code will add all of the following methods to the controller: 
     16  # 
     17  #  class WeblogController < ActionController::Base 
     18  #    verify :method => :post, :only => [ :destroy, :create, :update ], 
     19  #           :redirect_to => { :action => :list } 
     20  # 
     21  #    def index 
     22  #      list 
     23  #    end 
     24  # 
     25  #    def list 
     26  #      @entries = Entry.find(:all) 
     27  #      render_scaffold "list" 
     28  #    end 
     29  # 
     30  #    def show 
     31  #      @entry = Entry.find(params[:id]) 
     32  #      render_scaffold 
     33  #    end 
     34  # 
     35  #    def destroy 
     36  #      Entry.find(params[:id]).destroy 
     37  #      redirect_to :action => "list" 
     38  #    end 
     39  # 
     40  #    def new 
     41  #      @entry = Entry.new 
     42  #      render_scaffold 
     43  #    end 
     44  # 
     45  #    def create 
     46  #      @entry = Entry.new(params[:entry]) 
     47  #      if @entry.save 
     48  #        flash[:notice] = "Entry was successfully created" 
     49  #        redirect_to :action => "list" 
     50  #      else 
     51  #        render_scaffold('new') 
     52  #      end 
     53  #    end 
     54  # 
     55  #    def edit 
     56  #      @entry = Entry.find(params[:id]) 
     57  #      render_scaffold 
     58  #    end 
     59  # 
     60  #    def update 
     61  #      @entry = Entry.find(params[:id]) 
     62  #      @entry.attributes = params[:entry] 
     63  # 
     64  #      if @entry.save 
     65  #        flash[:notice] = "Entry was successfully updated" 
     66  #        redirect_to :action => "show", :id => @entry 
     67  #      else 
     68  #        render_scaffold('edit') 
     69  #      end 
     70  #    end 
     71  #  end 
     72  # 
     73  # The <tt>render_scaffold</tt> method will first check to see if you've made your own template (like "weblog/show.erb" for 
     74  # the show action) and if not, then render the generic template for that action. This gives you the possibility of using the 
     75  # scaffold while you're building your specific application. Start out with a totally generic setup, then replace one template 
     76  # and one action at a time while relying on the rest of the scaffolded templates and actions. 
     77  module ClassMethods 
     78    # Adds a swath of generic CRUD actions to the controller. The +model_id+ is automatically converted into a class name unless 
     79    # one is specifically provide through <tt>options[:class_name]</tt>. So <tt>scaffold :post</tt> would use Post as the class 
     80    # and @post/@posts for the instance variables. 
     81    # 
     82    # It's possible to use more than one scaffold in a single controller by specifying <tt>options[:suffix] = true</tt>. This will 
     83    # make <tt>scaffold :post, :suffix => true</tt> use method names like list_post, show_post, and create_post 
     84    # instead of just list, show, and post. If suffix is used, then no index method is added. 
     85    def scaffold(model_id, options = {}) 
     86      options.assert_valid_keys(:class_name, :suffix) 
     87 
     88      singular_name = model_id.to_s 
     89      class_name    = options[:class_name] || singular_name.camelize 
     90      plural_name   = singular_name.pluralize 
     91      suffix        = options[:suffix] ? "_#{singular_name}" : "" 
     92 
     93      unless options[:suffix] 
     94        module_eval <<-"end_eval", __FILE__, __LINE__ 
     95          def index 
     96            list 
     97          end 
     98        end_eval 
     99      end 
     100 
     101      module_eval <<-"end_eval", __FILE__, __LINE__ 
     102 
     103        verify :method => :post, :only => [ :destroy#{suffix}, :create#{suffix}, :update#{suffix} ], 
     104               :redirect_to => { :action => :list#{suffix} } 
     105 
     106 
     107        def list#{suffix} 
     108          @#{singular_name}_pages, @#{plural_name} = paginate :#{plural_name}, :per_page => 10 
     109          render#{suffix}_scaffold "list#{suffix}" 
     110        end 
     111 
     112        def show#{suffix} 
     113          @#{singular_name} = #{class_name}.find(params[:id]) 
     114          render#{suffix}_scaffold 
     115        end 
     116 
     117        def destroy#{suffix} 
     118          #{class_name}.find(params[:id]).destroy 
     119          redirect_to :action => "list#{suffix}" 
     120        end 
     121 
     122        def new#{suffix} 
     123          @#{singular_name} = #{class_name}.new 
     124          render#{suffix}_scaffold 
     125        end 
     126 
     127        def create#{suffix} 
     128          @#{singular_name} = #{class_name}.new(params[:#{singular_name}]) 
     129          if @#{singular_name}.save 
     130            flash[:notice] = "#{class_name} was successfully created" 
     131            redirect_to :action => "list#{suffix}" 
     132          else 
     133            render#{suffix}_scaffold('new') 
     134          end 
     135        end 
     136 
     137        def edit#{suffix} 
     138          @#{singular_name} = #{class_name}.find(params[:id]) 
     139          render#{suffix}_scaffold 
     140        end 
     141 
     142        def update#{suffix} 
     143          @#{singular_name} = #{class_name}.find(params[:id]) 
     144          @#{singular_name}.attributes = params[:#{singular_name}] 
     145 
     146          if @#{singular_name}.save 
     147            flash[:notice] = "#{class_name} was successfully updated" 
     148            redirect_to :action => "show#{suffix}", :id => @#{singular_name} 
     149          else 
     150            render#{suffix}_scaffold('edit') 
     151          end 
     152        end 
     153 
     154        private 
     155          def render#{suffix}_scaffold(action=nil) 
     156            action ||= caller_method_name(caller) 
     157            # logger.info ("testing template:" + "\#{self.class.controller_path}/\#{action}") if logger 
     158 
     159            if template_exists?("\#{self.class.controller_path}/\#{action}") 
     160              render :action => action 
     161            else 
     162              @scaffold_class = #{class_name} 
     163              @scaffold_singular_name, @scaffold_plural_name = "#{singular_name}", "#{plural_name}" 
     164              @scaffold_suffix = "#{suffix}" 
     165              add_instance_variables_to_assigns 
     166 
     167              @template.instance_variable_set("@content_for_layout", @template.render_file(scaffold_path(action.sub(/#{suffix}$/, "")), false)) 
     168 
     169              if !active_layout.nil? 
     170                render :file => active_layout, :use_full_path => true 
     171              else 
     172                render :file => scaffold_path('layout') 
     173              end 
     174            end 
     175          end 
     176 
     177          def scaffold_path(template_name) 
     178            File.dirname(__FILE__) + "/templates/" + template_name + ".erb" 
     179          end 
     180 
     181          def caller_method_name(caller) 
     182            caller.first.scan(/`(.*)'/).first.first # ' ruby-mode 
     183          end 
     184      end_eval 
     185    end 
     186  end 
     187end 
  • plugins/scaffolding/lib/templates/new.erb

    old new  
     1<h1>New <%= @scaffold_singular_name %></h1> 
     2 
     3<%= error_messages_for(@scaffold_singular_name) %> 
     4<%= form(@scaffold_singular_name, :action => "create#{@scaffold_suffix}") %> 
     5 
     6<%= link_to "Back", :action => "list#{@scaffold_suffix}" %> 
  • plugins/scaffolding/lib/templates/list.erb

    old new  
     1<h1>Listing <%= @scaffold_plural_name %></h1> 
     2 
     3<table> 
     4  <tr> 
     5  <% for column in @scaffold_class.content_columns %> 
     6    <th><%= column.human_name %></th> 
     7  <% end %> 
     8  </tr> 
     9   
     10<% for entry in instance_variable_get("@#{@scaffold_plural_name}") %> 
     11  <tr> 
     12  <% for column in @scaffold_class.content_columns %> 
     13    <td><%= entry.send(column.name) %></td> 
     14  <% end %> 
     15    <td><%= link_to "Show", :action => "show#{@scaffold_suffix}", :id => entry %></td> 
     16    <td><%= link_to "Edit", :action => "edit#{@scaffold_suffix}", :id => entry %></td> 
     17    <td><%= link_to "Destroy", {:action => "destroy#{@scaffold_suffix}", :id => entry}, { :confirm => "Are you sure?", :method => :post } %></td> 
     18  </tr> 
     19<% end %> 
     20</table> 
     21 
     22<%= link_to "Previous page", { :page => instance_variable_get("@#{@scaffold_singular_name}_pages").current.previous } if instance_variable_get("@#{@scaffold_singular_name}_pages").current.previous %> 
     23<%= link_to "Next page", { :page => instance_variable_get("@#{@scaffold_singular_name}_pages").current.next } if instance_variable_get("@#{@scaffold_singular_name}_pages").current.next %>  
     24 
     25<br /> 
     26 
     27<%= link_to "New #{@scaffold_singular_name}", :action => "new#{@scaffold_suffix}" %> 
  • plugins/scaffolding/lib/templates/layout.erb

    old new  
     1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
     2   "http://www.w3.org/TR/html4/loose.dtd"> 
     3<html> 
     4<head> 
     5  <title>Scaffolding</title> 
     6  <style> 
     7    body { background-color: #fff; color: #333; } 
     8 
     9    body, p, ol, ul, td { 
     10      font-family: verdana, arial, helvetica, sans-serif; 
     11      font-size:   13px; 
     12      line-height: 18px; 
     13    } 
     14 
     15    pre { 
     16      background-color: #eee; 
     17      padding: 10px; 
     18      font-size: 11px; 
     19    } 
     20 
     21    a { color: #000; } 
     22    a:visited { color: #666; } 
     23    a:hover { color: #fff; background-color:#000; } 
     24 
     25    .fieldWithErrors { 
     26      padding: 2px; 
     27      background-color: red; 
     28      display: table; 
     29    } 
     30 
     31    #errorExplanation { 
     32      width: 400px; 
     33      border: 2px solid red; 
     34      padding: 7px; 
     35      padding-bottom: 12px; 
     36      margin-bottom: 20px; 
     37      background-color: #f0f0f0; 
     38    } 
     39 
     40    #errorExplanation h2 { 
     41      text-align: left; 
     42      font-weight: bold; 
     43      padding: 5px 5px 5px 15px; 
     44      font-size: 12px; 
     45      margin: -7px; 
     46      background-color: #c00; 
     47      color: #fff; 
     48    } 
     49 
     50    #errorExplanation p { 
     51      color: #333; 
     52      margin-bottom: 0; 
     53      padding: 5px; 
     54    } 
     55 
     56    #errorExplanation ul li { 
     57      font-size: 12px; 
     58      list-style: square; 
     59    } 
     60  </style> 
     61</head> 
     62<body> 
     63 
     64<p style="color: green"><%= flash[:notice] %></p> 
     65 
     66<%= yield %> 
     67 
     68</body> 
     69</html> 
  • plugins/scaffolding/lib/templates/show.erb

    old new  
     1<% for column in @scaffold_class.content_columns %> 
     2  <p> 
     3    <b><%= column.human_name %>:</b> 
     4    <%= instance_variable_get("@#{@scaffold_singular_name}").send(column.name) %> 
     5  </p> 
     6<% end %> 
     7 
     8<%= link_to "Edit", :action => "edit#{@scaffold_suffix}", :id => instance_variable_get("@#{@scaffold_singular_name}") %> | 
     9<%= link_to "Back", :action => "list#{@scaffold_suffix}" %> 
  • plugins/scaffolding/lib/templates/edit.erb

    old new  
     1<h1>Editing <%= @scaffold_singular_name %></h1> 
     2 
     3<%= error_messages_for(@scaffold_singular_name) %> 
     4<%= form(@scaffold_singular_name, :action => "update#{@scaffold_suffix}") %> 
     5 
     6<%= link_to "Show", :action => "show#{@scaffold_suffix}", :id => instance_variable_get("@#{@scaffold_singular_name}") %> | 
     7<%= link_to "Back", :action => "list#{@scaffold_suffix}" %> 
  • plugins/scaffolding/MIT-LICENSE

    old new  
     1Copyright (c) 2004-2007 David Heinemeier Hansson 
     2 
     3Permission is hereby granted, free of charge, to any person obtaining 
     4a copy of this software and associated documentation files (the 
     5"Software"), to deal in the Software without restriction, including 
     6without limitation the rights to use, copy, modify, merge, publish, 
     7distribute, sublicense, and/or sell copies of the Software, and to 
     8permit persons to whom the Software is furnished to do so, subject to 
     9the following conditions: 
     10 
     11The above copyright notice and this permission notice shall be 
     12included in all copies or substantial portions of the Software. 
     13 
     14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
     15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
     17NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
     18LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
     19OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
     20WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  • plugins/scaffolding/README

    old new  
     1Scaffolding 
     2=========== 
     3 
     4Scaffolding 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: 
     5 
     6The render_scaffold 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. 
     7 
     8Example 
     9======= 
     10 
     11 class WeblogController < ActionController::Base 
     12   scaffold :entry 
     13 end 
     14 
     15This tiny piece of code will add all of the following methods to the controller: 
     16 
     17 class WeblogController < ActionController::Base 
     18   verify :method => :post, :only => [ :destroy, :create, :update ], 
     19          :redirect_to => { :action => :list } 
     20 
     21   def index 
     22     list 
     23   end 
     24 
     25   def list 
     26     @entries = Entry.find(:all) 
     27     render_scaffold "list" 
     28   end 
     29 
     30   def show 
     31     @entry = Entry.find(params[:id]) 
     32     render_scaffold 
     33   end 
     34 
     35   def destroy 
     36     Entry.find(params[:id]).destroy 
     37     redirect_to :action => "list" 
     38   end 
     39 
     40   def new 
     41     @entry = Entry.new 
     42     render_scaffold 
     43   end 
     44 
     45   def create 
     46     @entry = Entry.new(params[:entry]) 
     47     if @entry.save 
     48       flash[:notice] = "Entry was successfully created" 
     49       redirect_to :action => "list" 
     50     else 
     51       render_scaffold('new') 
     52     end 
     53   end 
     54 
     55   def edit 
     56     @entry = Entry.find(params[:id]) 
     57     render_scaffold 
     58   end 
     59 
     60   def update 
     61     @entry = Entry.find(params[:id]) 
     62     @entry.attributes = params[:entry] 
     63 
     64     if @entry.save 
     65       flash[:notice] = "Entry was successfully updated" 
     66       redirect_to :action => "show", :id => @entry 
     67     else 
     68       render_scaffold('edit') 
     69     end 
     70   end 
     71 end 
     72 
     73 
     74Copyright (c) 2004-2007 David Heinemeier Hansson, released under the MIT license