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

Changeset 6062

Show
Ignore:
Timestamp:
01/28/07 08:20:04 (2 years ago)
Author:
bitsweat
Message:

Resource member routes require :id, eliminating the ambiguous overlap with collection routes. Closes #7229.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/CHANGELOG

    r6055 r6062  
    11*SVN* 
     2 
     3* Resource member routes require :id, eliminating the ambiguous overlap with collection routes.  #7229 [dkubb] 
    24 
    35* Remove deprecated assertions.  [Jeremy Kemper] 
  • trunk/actionpack/lib/action_controller/resources.rb

    r5877 r6062  
    323323      def map_collection_actions(map, resource) 
    324324        resource.collection_methods.each do |method, actions| 
    325           route_options = requirements_for(method) 
    326  
    327325          actions.each do |action| 
    328             map.named_route( 
    329               "#{resource.name_prefix}#{action}_#{resource.plural}",  
    330               "#{resource.path};#{action}",  
    331               route_options.merge(:action => action.to_s) 
    332             ) 
    333  
    334             map.named_route( 
    335               "formatted_#{resource.name_prefix}#{action}_#{resource.plural}", 
    336               "#{resource.path}.:format;#{action}", 
    337               route_options.merge(:action => action.to_s) 
    338             ) 
     326            action_options = action_options_for(action, resource, method) 
     327            map.named_route("#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path};#{action}", action_options) 
     328            map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path}.:format;#{action}", action_options) 
    339329          end 
    340330        end 
     
    342332 
    343333      def map_default_collection_actions(map, resource) 
    344         map.named_route("#{resource.name_prefix}#{resource.plural}", resource.path, :action => "index", :conditions => { :method => :get }) 
    345         map.named_route("formatted_#{resource.name_prefix}#{resource.plural}", "#{resource.path}.:format", :action => "index", :conditions => { :method => :get }) 
    346  
    347         map.connect(resource.path, :action => "create", :conditions => { :method => :post }) 
    348         map.connect("#{resource.path}.:format", :action => "create", :conditions => { :method => :post }) 
     334        index_action_options = action_options_for("index", resource) 
     335        map.named_route("#{resource.name_prefix}#{resource.plural}", resource.path, index_action_options) 
     336        map.named_route("formatted_#{resource.name_prefix}#{resource.plural}", "#{resource.path}.:format", index_action_options) 
     337 
     338        create_action_options = action_options_for("create", resource) 
     339        map.connect(resource.path, create_action_options) 
     340        map.connect("#{resource.path}.:format", create_action_options) 
    349341      end 
    350342 
    351343      def map_default_singleton_actions(map, resource) 
    352         map.connect(resource.path, :action => "create", :conditions => { :method => :post }) 
    353         map.connect("#{resource.path}.:format", :action => "create", :conditions => { :method => :post }) 
     344        create_action_options = action_options_for("create", resource) 
     345        map.connect(resource.path, create_action_options) 
     346        map.connect("#{resource.path}.:format", create_action_options) 
    354347      end 
    355348 
    356349      def map_new_actions(map, resource) 
    357350        resource.new_methods.each do |method, actions| 
    358           route_options = requirements_for(method) 
    359351          actions.each do |action| 
     352            action_options = action_options_for(action, resource, method) 
    360353            if action == :new 
    361               map.named_route("#{resource.name_prefix}new_#{resource.singular}", resource.new_path, route_options.merge(:action => "new")
    362               map.named_route("formatted_#{resource.name_prefix}new_#{resource.singular}", "#{resource.new_path}.:format", route_options.merge(:action => "new")
     354              map.named_route("#{resource.name_prefix}new_#{resource.singular}", resource.new_path, action_options
     355              map.named_route("formatted_#{resource.name_prefix}new_#{resource.singular}", "#{resource.new_path}.:format", action_options
    363356            else 
    364               map.named_route("#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path};#{action}", route_options.merge(:action => action.to_s)
    365               map.named_route("formatted_#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path}.:format;#{action}", route_options.merge(:action => action.to_s)
     357              map.named_route("#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path};#{action}", action_options
     358              map.named_route("formatted_#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path}.:format;#{action}", action_options
    366359            end 
    367360          end 
    368361        end 
    369362      end 
    370        
     363 
    371364      def map_member_actions(map, resource) 
    372365        resource.member_methods.each do |method, actions| 
    373           route_options = requirements_for(method) 
    374  
    375366          actions.each do |action| 
    376             map.named_route("#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path};#{action}", route_options.merge(:action => action.to_s)) 
    377             map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path}.:format;#{action}", route_options.merge(:action => action.to_s)) 
    378           end 
    379         end 
    380  
    381         map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, :action => "show", :conditions => { :method => :get }) 
    382         map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", :action => "show", :conditions => { :method => :get }) 
    383  
    384         map.connect(resource.member_path, :action => "update", :conditions => { :method => :put }) 
    385         map.connect("#{resource.member_path}.:format", :action => "update", :conditions => { :method => :put }) 
    386  
    387         map.connect(resource.member_path, :action => "destroy", :conditions => { :method => :delete }) 
    388         map.connect("#{resource.member_path}.:format", :action => "destroy", :conditions => { :method => :delete }) 
    389       end 
    390  
    391       def requirements_for(method) 
    392         method == :any ? {} : { :conditions => { :method => method } } 
     367            action_options = action_options_for(action, resource, method) 
     368            map.named_route("#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path};#{action}", action_options) 
     369            map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path}.:format;#{action}",action_options) 
     370          end 
     371        end 
     372 
     373        show_action_options = action_options_for("show", resource) 
     374        map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options) 
     375        map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", show_action_options) 
     376 
     377        update_action_options = action_options_for("update", resource) 
     378        map.connect(resource.member_path, update_action_options) 
     379        map.connect("#{resource.member_path}.:format", update_action_options) 
     380 
     381        destroy_action_options = action_options_for("destroy", resource) 
     382        map.connect(resource.member_path, destroy_action_options) 
     383        map.connect("#{resource.member_path}.:format", destroy_action_options) 
     384      end 
     385 
     386      def conditions_for(method) 
     387        { :conditions => method == :any ? {} : { :method => method } } 
     388      end 
     389 
     390      def action_options_for(action, resource, method = nil) 
     391        default_options = { :action => action.to_s } 
     392        require_id = resource.kind_of?(SingletonResource) ? {} : { :requirements => { :id => Regexp.new("[^#{Routing::SEPARATORS.join}]+") } } 
     393        case default_options[:action] 
     394          when "index", "new" : default_options.merge(conditions_for(method || :get)) 
     395          when "create"       : default_options.merge(conditions_for(method || :post)) 
     396          when "show", "edit" : default_options.merge(conditions_for(method || :get)).merge(require_id) 
     397          when "update"       : default_options.merge(conditions_for(method || :put)).merge(require_id) 
     398          when "destroy"      : default_options.merge(conditions_for(method || :delete)).merge(require_id) 
     399          else                  default_options.merge(conditions_for(method)) 
     400        end 
    393401      end 
    394402  end 
  • trunk/actionpack/test/controller/resources_test.rb

    r5974 r6062  
    2626    assert_resource_methods [:upload, :fix],          resource, :member,     :post 
    2727    assert_resource_methods [:new, :preview, :draft], resource, :new,        :get 
     28  end 
     29 
     30  def test_should_resource_controller_name_equal_resource_name_by_default 
     31    resource = ActionController::Resources::Resource.new(:messages, {}) 
     32    assert_equal 'messages', resource.controller 
     33  end 
     34 
     35  def test_should_resource_controller_name_equal_controller_option 
     36    resource = ActionController::Resources::Resource.new(:messages, :controller => 'posts') 
     37    assert_equal 'posts', resource.controller 
     38  end 
     39 
     40  def test_should_all_singleton_paths_be_the_same 
     41    [ :path, :nesting_path_prefix, :member_path ].each do |method| 
     42      resource = ActionController::Resources::SingletonResource.new(:messages, :path_prefix => 'admin') 
     43      assert_equal 'admin/messages', resource.send(method) 
     44    end 
    2845  end 
    2946 
     
    117134  end 
    118135 
    119  
    120136  def test_with_new_action 
    121137    with_restful_routing :messages, :new => { :preview => :post } do 
     
    281297  end 
    282298 
     299  def test_should_not_allow_delete_or_put_on_collection_path 
     300    controller_name = :messages 
     301    with_restful_routing controller_name do 
     302      options = { :controller => controller_name.to_s } 
     303      collection_path = "/#{controller_name}" 
     304 
     305      assert_raises(ActionController::RoutingError) do 
     306        assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put) 
     307      end 
     308 
     309      assert_raises(ActionController::RoutingError) do 
     310        assert_recognizes(options.merge(:action => 'destroy'), :path => collection_path, :method => :delete) 
     311      end 
     312    end 
     313  end 
     314 
    283315  protected 
    284316    def with_restful_routing(*args) 
     
    310342      (options[:options] ||= {})[:controller] = controller_name.to_s 
    311343 
    312       collection_path = "/#{options[:path_prefix]}#{controller_name}" 
    313       member_path = "#{collection_path}/1" 
    314       new_path = "#{collection_path}/new" 
     344      collection_path            = "/#{options[:path_prefix]}#{controller_name}" 
     345      member_path                = "#{collection_path}/1" 
     346      new_path                   = "#{collection_path}/new" 
     347      edit_member_path           = "#{member_path};edit" 
     348      formatted_edit_member_path = "#{member_path}.xml;edit" 
    315349 
    316350      with_options(options[:options]) do |controller| 
    317351        controller.assert_routing collection_path,            :action => 'index' 
    318         controller.assert_routing "#{collection_path}.xml" ,  :action => 'index', :format => 'xml' 
    319352        controller.assert_routing new_path,                   :action => 'new' 
    320353        controller.assert_routing member_path,                :action => 'show', :id => '1' 
    321         controller.assert_routing "#{member_path};edit",      :action => 'edit', :id => '1' 
     354        controller.assert_routing edit_member_path,           :action => 'edit', :id => '1' 
     355        controller.assert_routing "#{collection_path}.xml",   :action => 'index',            :format => 'xml' 
     356        controller.assert_routing "#{new_path}.xml",          :action => 'new',              :format => 'xml' 
    322357        controller.assert_routing "#{member_path}.xml",       :action => 'show', :id => '1', :format => 'xml' 
    323       end 
    324  
    325       assert_recognizes( 
    326         options[:options].merge(:action => 'create'), 
    327         :path => collection_path, :method => :post) 
    328  
    329       assert_recognizes( 
    330         options[:options].merge(:action => 'update', :id => '1'), 
    331         :path => member_path, :method => :put) 
    332  
    333       assert_recognizes( 
    334         options[:options].merge(:action => 'destroy', :id => '1'), 
    335         :path => member_path, :method => :delete) 
     358        controller.assert_routing formatted_edit_member_path, :action => 'edit', :id => '1', :format => 'xml' 
     359      end 
     360 
     361      assert_recognizes(options[:options].merge(:action => 'index'),               :path => collection_path,  :method => :get) 
     362      assert_recognizes(options[:options].merge(:action => 'new'),                 :path => new_path,         :method => :get) 
     363      assert_recognizes(options[:options].merge(:action => 'create'),              :path => collection_path,  :method => :post) 
     364      assert_recognizes(options[:options].merge(:action => 'show',    :id => '1'), :path => member_path,      :method => :get) 
     365      assert_recognizes(options[:options].merge(:action => 'edit',    :id => '1'), :path => edit_member_path, :method => :get) 
     366      assert_recognizes(options[:options].merge(:action => 'update',  :id => '1'), :path => member_path,      :method => :put) 
     367      assert_recognizes(options[:options].merge(:action => 'destroy', :id => '1'), :path => member_path,      :method => :delete) 
     368 
     369      assert_recognizes(options[:options].merge(:action => 'index',               :format => 'xml'), :path => "#{collection_path}.xml",   :method => :get) 
     370      assert_recognizes(options[:options].merge(:action => 'new',                 :format => 'xml'), :path => "#{new_path}.xml",          :method => :get) 
     371      assert_recognizes(options[:options].merge(:action => 'create',              :format => 'xml'), :path => "#{collection_path}.xml",   :method => :post) 
     372      assert_recognizes(options[:options].merge(:action => 'show',    :id => '1', :format => 'xml'), :path => "#{member_path}.xml",       :method => :get) 
     373      assert_recognizes(options[:options].merge(:action => 'edit',    :id => '1', :format => 'xml'), :path => formatted_edit_member_path, :method => :get) 
     374      assert_recognizes(options[:options].merge(:action => 'update',  :id => '1', :format => 'xml'), :path => "#{member_path}.xml",       :method => :put) 
     375      assert_recognizes(options[:options].merge(:action => 'destroy', :id => '1', :format => 'xml'), :path => "#{member_path}.xml",       :method => :delete) 
    336376 
    337377      yield options[:options] if block_given? 
     
    355395      name_prefix = options[:name_prefix] 
    356396 
    357       assert_named_route "#{full_prefix}",        "#{name_prefix}#{controller_name}_path",           options[:options] 
    358       assert_named_route "#{full_prefix}.xml",    "formatted_#{name_prefix}#{controller_name}_path", options[:options].merge(:format => 'xml') 
    359       assert_named_route "#{full_prefix}/new",    "#{name_prefix}new_#{singular_name}_path",         options[:options] 
    360       assert_named_route "#{full_prefix}/1",      "#{name_prefix}#{singular_name}_path",             options[:options].merge(:id => '1') 
    361       assert_named_route "#{full_prefix}/1;edit", "#{name_prefix}edit_#{singular_name}_path",        options[:options].merge(:id => '1') 
    362       assert_named_route "#{full_prefix}/1.xml",  "formatted_#{name_prefix}#{singular_name}_path",   options[:options].merge(:format => 'xml', :id => '1') 
     397      assert_named_route "#{full_prefix}",            "#{name_prefix}#{controller_name}_path",              options[:options] 
     398      assert_named_route "#{full_prefix}/new",        "#{name_prefix}new_#{singular_name}_path",            options[:options] 
     399      assert_named_route "#{full_prefix}/1",          "#{name_prefix}#{singular_name}_path",                options[:options].merge(:id => '1') 
     400      assert_named_route "#{full_prefix}/1;edit",     "#{name_prefix}edit_#{singular_name}_path",           options[:options].merge(:id => '1') 
     401      assert_named_route "#{full_prefix}.xml",        "formatted_#{name_prefix}#{controller_name}_path",    options[:options].merge(            :format => 'xml') 
     402      assert_named_route "#{full_prefix}/new.xml",    "formatted_#{name_prefix}new_#{singular_name}_path",  options[:options].merge(            :format => 'xml') 
     403      assert_named_route "#{full_prefix}/1.xml",      "formatted_#{name_prefix}#{singular_name}_path",      options[:options].merge(:id => '1', :format => 'xml') 
     404      assert_named_route "#{full_prefix}/1.xml;edit", "formatted_#{name_prefix}edit_#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') 
    363405      yield options[:options] if block_given? 
    364406    end 
     
    366408    def assert_singleton_routes_for(singleton_name, options = {}) 
    367409      (options[:options] ||= {})[:controller] ||= singleton_name.to_s 
    368        
    369       full_path = "/#{options[:path_prefix]}#{singleton_name}" 
     410 
     411      full_path           = "/#{options[:path_prefix]}#{singleton_name}" 
     412      new_path            = "#{full_path}/new" 
     413      edit_path           = "#{full_path};edit" 
     414      formatted_edit_path = "#{full_path}.xml;edit" 
     415 
    370416      with_options options[:options] do |controller| 
    371         controller.assert_routing full_path,          :action => 'show' 
    372         controller.assert_routing "#{full_path}.xml", :action => 'show', :format => 'xml' 
    373         controller.assert_routing "#{full_path}/new", :action => 'new' 
    374         controller.assert_routing "#{full_path};edit", :action => 'edit' 
    375       end 
    376  
     417        controller.assert_routing full_path,           :action => 'show' 
     418        controller.assert_routing new_path,            :action => 'new' 
     419        controller.assert_routing edit_path,           :action => 'edit' 
     420        controller.assert_routing "#{full_path}.xml",  :action => 'show', :format => 'xml' 
     421        controller.assert_routing "#{new_path}.xml",   :action => 'new',  :format => 'xml' 
     422        controller.assert_routing formatted_edit_path, :action => 'edit', :format => 'xml' 
     423      end 
     424 
     425      assert_recognizes(options[:options].merge(:action => 'show'),    :path => full_path, :method => :get) 
     426      assert_recognizes(options[:options].merge(:action => 'new'),     :path => new_path,  :method => :get) 
     427      assert_recognizes(options[:options].merge(:action => 'edit'),    :path => edit_path, :method => :get) 
    377428      assert_recognizes(options[:options].merge(:action => 'create'),  :path => full_path, :method => :post) 
    378429      assert_recognizes(options[:options].merge(:action => 'update'),  :path => full_path, :method => :put) 
    379430      assert_recognizes(options[:options].merge(:action => 'destroy'), :path => full_path, :method => :delete) 
     431 
     432      assert_recognizes(options[:options].merge(:action => 'show',    :format => 'xml'), :path => "#{full_path}.xml",  :method => :get) 
     433      assert_recognizes(options[:options].merge(:action => 'new',     :format => 'xml'), :path => "#{new_path}.xml",   :method => :get) 
     434      assert_recognizes(options[:options].merge(:action => 'edit',    :format => 'xml'), :path => formatted_edit_path, :method => :get) 
     435      assert_recognizes(options[:options].merge(:action => 'create',  :format => 'xml'), :path => "#{full_path}.xml",  :method => :post) 
     436      assert_recognizes(options[:options].merge(:action => 'update',  :format => 'xml'), :path => "#{full_path}.xml",  :method => :put) 
     437      assert_recognizes(options[:options].merge(:action => 'destroy', :format => 'xml'), :path => "#{full_path}.xml",  :method => :delete) 
    380438 
    381439      yield options[:options] if block_given? 
     
    389447      get :show, options[:options] 
    390448      options[:options].delete :action 
    391        
     449 
    392450      full_path = "/#{options[:path_prefix]}#{singleton_name}" 
    393        
    394       assert_named_route "#{full_path}",    "#{singleton_name}_path",            options[:options] 
    395       assert_named_route "#{full_path}.xml", "formatted_#{singleton_name}_path", options[:options].merge(:format => 'xml') 
    396       assert_named_route "#{full_path}/new", "new_#{singleton_name}_path", options[:options] 
    397       assert_named_route "#{full_path};edit", "edit_#{singleton_name}_path", options[:options] 
     451 
     452      assert_named_route "#{full_path}",          "#{singleton_name}_path",                options[:options] 
     453      assert_named_route "#{full_path}/new",      "new_#{singleton_name}_path",            options[:options] 
     454      assert_named_route "#{full_path};edit",     "edit_#{singleton_name}_path",           options[:options] 
     455      assert_named_route "#{full_path}.xml",      "formatted_#{singleton_name}_path",      options[:options].merge(:format => 'xml') 
     456      assert_named_route "#{full_path}/new.xml",  "formatted_new_#{singleton_name}_path",  options[:options].merge(:format => 'xml') 
     457      assert_named_route "#{full_path}.xml;edit", "formatted_edit_#{singleton_name}_path", options[:options].merge(:format => 'xml') 
    398458    end 
    399459