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

Ticket #6432: polymorphic_nested_routes.patch

File polymorphic_nested_routes.patch, 10.7 kB (added by gravelpup, 3 years ago)

This patch relative to rails_root (old version was relative to actionpack)

  • actionpack/test/template/url_helper_test.rb

    old new  
    375375  end 
    376376end 
    377377 
     378class Session 
     379  attr_accessor :id, :workshop_id, :new_record 
     380 
     381  def initialize(id, new_record) 
     382    @id, @new_record = id, new_record 
     383  end 
     384   
     385  #   def save; @id = 1; @post_id = 1 end 
     386 
     387  def new_record? 
     388    @new_record 
     389  end 
     390   
     391  def to_s 
     392    id.to_s 
     393  end 
     394end 
     395 
    378396class PolymorphicControllerTest < Test::Unit::TestCase 
    379397  class WorkshopsController < ActionController::Base 
    380398    self.view_paths = ["#{File.dirname(__FILE__)}/../fixtures/"] 
     
    394412    def rescue_action(e) raise e end 
    395413  end 
    396414 
     415  class SessionsController < ActionController::Base 
     416    self.view_paths = ["#{File.dirname(__FILE__)}/../fixtures/"] 
     417 
     418    def self.controller_path; 'sessions' end 
     419 
     420    def index 
     421      @workshop = Workshop.new(params[:workshop_id], false) 
     422      @session = Session.new(1, true) 
     423      render :inline => "<%= url_for([@workshop, @session]) %>\n<%= link_to('Session', [@workshop, @session]) %>" 
     424    end 
     425 
     426    def show 
     427      @workshop = Workshop.new(params[:workshop_id], false) 
     428      @session = Session.new(params[:id], false) 
     429      render :inline => "<%= url_for([@workshop, @session]) %>\n<%= link_to('Session', [@workshop, @session]) %>" 
     430    end 
     431 
     432    def rescue_action(e) raise e end 
     433  end 
     434 
    397435  include ActionView::Helpers::UrlHelper 
    398436 
    399437  def setup 
    400438    @request    = ActionController::TestRequest.new 
    401439    @response   = ActionController::TestResponse.new 
    402     @controller = WorkshopsController.new 
    403440  end 
    404441 
    405442  def test_new_resource 
     443    @controller = WorkshopsController.new 
     444   
    406445    with_restful_routing do 
    407446      get :index 
    408447      assert_equal "/workshops\n<a href=\"/workshops\">Workshop</a>", @response.body 
     
    410449  end 
    411450 
    412451  def test_existing_resource 
     452    @controller = WorkshopsController.new 
     453 
    413454    with_restful_routing do 
    414455      get :show, :id => 1 
    415456      assert_equal "/workshops/1\n<a href=\"/workshops/1\">Workshop</a>", @response.body 
    416457    end 
    417458  end 
    418459 
     460  def test_new_nested_resource 
     461    @controller = SessionsController.new 
     462   
     463    with_restful_routing do 
     464      get :index, :workshop_id => 1 
     465      assert_equal "/workshops/1/sessions\n<a href=\"/workshops/1/sessions\">Session</a>", @response.body 
     466    end 
     467  end 
     468 
     469  def test_existing_nested_resource 
     470    @controller = SessionsController.new 
     471   
     472    with_restful_routing do 
     473      get :show, :workshop_id => 1, :id => 1 
     474      assert_equal "/workshops/1/sessions/1\n<a href=\"/workshops/1/sessions/1\">Session</a>", @response.body 
     475    end 
     476  end 
     477 
    419478  protected 
    420479    def with_restful_routing 
    421480      with_routing do |set| 
    422481        set.draw do |map| 
    423           map.resources :workshops 
     482          map.resources :workshops do |w| 
     483           w.resources :sessions 
     484          end 
    424485        end 
    425486        yield 
    426487      end 
  • actionpack/test/template/form_helper_test.rb

    old new  
    1515      @new_record 
    1616    end 
    1717  end 
     18   
     19  class Comment 
     20    attr_reader :id 
     21    attr_reader :post_id 
     22    def save; @id = 1; @post_id = 1 end 
     23    def new_record?; @id.nil? end 
     24    def name 
     25      @id.nil? ? 'new comment' : "comment ##{@id}" 
     26    end 
     27  end 
    1828end 
    1929 
     30class Comment::Nested < Comment; end 
     31 
     32class Test::Unit::TestCase 
     33  protected 
     34    def comments_path(post) 
     35      "/posts/#{post.id}/comments" 
     36    end 
     37     
     38    def comment_path(post, comment) 
     39      "/posts/#{post.id}/comments/#{comment.id}" 
     40    end 
     41end 
     42 
    2043class FormHelperTest < Test::Unit::TestCase 
    2144  include ActionView::Helpers::FormHelper 
    2245  include ActionView::Helpers::FormTagHelper 
     
    2851 
    2952  def setup 
    3053    @post = Post.new 
     54    @comment = Comment.new 
    3155    def @post.errors()  
    3256      Class.new{  
    3357        def on(field); "can't be empty" if field == "author_name"; end  
     
    579603    assert_equal expected, _erbout 
    580604  end 
    581605 
     606  def test_form_for_with_existing_object_in_list 
     607    @post.new_record = false 
     608    @comment.save 
     609    _erbout = '' 
     610    form_for([ @post, @comment ]) {} 
     611 
     612    expected = "<form action=\"#{comment_path(@post, @comment)}\" class=\"edit_comment\" id=\"edit_comment_1\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>" 
     613    assert_dom_equal expected, _erbout 
     614  end 
     615 
     616  def test_form_for_with_new_object_in_list 
     617    @post.new_record = false 
     618    _erbout = '' 
     619    form_for([ @post, @comment ]) {} 
     620   
     621    expected = "<form action=\"#{comments_path(@post)}\" class=\"new_comment\" id=\"new_comment\" method=\"post\"></form>" 
     622    assert_dom_equal expected, _erbout 
     623  end 
     624 
    582625  def test_form_for_with_existing_object_and_custom_url 
    583626    _erbout = '' 
    584627 
     
    600643 
    601644 
    602645  protected 
    603     def polymorphic_path(record) 
    604       if record.new_record? 
    605         "/posts" 
     646    def polymorphic_path(object, *nested_objects) 
     647      if nested_objects.empty? 
     648        if object.new_record? 
     649          "/posts" 
     650        else 
     651          "/posts/#{object.id}" 
     652        end 
    606653      else 
    607         "/posts/#{record.id}" 
     654        if object.new_record? 
     655          "/posts/123/comments" 
     656        else 
     657          "/posts/123/comments/#{object.id}" 
     658        end 
    608659      end 
    609660    end 
    610661end 
  • actionpack/lib/action_controller/record_identifier.rb

    old new  
    2525  #     end 
    2626  #   end 
    2727  # 
    28   # As the example above shows, you can stop caring to a large extend what the actual id of the post is. You just know 
     28  # As the example above shows, you can stop caring to a large extent what the actual id of the post is. You just know 
    2929  # that one is being assigned and that the subsequent calls in redirect_to and the RJS expect that same naming  
    3030  # convention and allows you to write less code if you follow it. 
    3131  module RecordIdentifier 
  • actionpack/lib/action_controller/polymorphic_routes.rb

    old new  
    11module ActionController 
    22  module PolymorphicRoutes 
    3     def polymorphic_url(record_or_hash, options = {}) 
    4       record = extract_record(record_or_hash
     3    def polymorphic_url(record_or_hash_or_array, options = {}) 
     4      record = extract_record(record_or_hash_or_array
    55 
    66      case 
    77      when options[:action] == "new" 
    88        send( 
    9           action_prefix(options) + RecordIdentifier.singular_class_name(record) + routing_type(options) 
     9          build_named_route_call(record_or_hash_or_array, :singular, options) 
    1010        ) 
    1111 
    1212      when record.respond_to?(:new_record?) && record.new_record? 
    1313        send( 
    14           action_prefix(options) + RecordIdentifier.plural_class_name(record) + routing_type(options) 
     14          build_named_route_call(record_or_hash_or_array, :plural, options) 
    1515        ) 
    1616 
    1717      else 
    1818        send( 
    19           action_prefix(options) + RecordIdentifier.singular_class_name(record) + routing_type(options), record_or_hash 
     19          build_named_route_call(record_or_hash_or_array, :singular, options), record_or_hash_or_array 
    2020        ) 
    2121      end 
    2222    end 
    2323 
    24     def polymorphic_path(record_or_hash
    25       polymorphic_url(record_or_hash, :routing_type => :path) 
     24    def polymorphic_path(record_or_hash_or_array
     25      polymorphic_url(record_or_hash_or_array, :routing_type => :path) 
    2626    end 
    2727 
    2828    %w( edit new formatted ).each do |action| 
     
    4444      end 
    4545 
    4646      def routing_type(options) 
    47         "_#{options[:routing_type] || "url"}" 
     47        "#{options[:routing_type] || "url"}" 
    4848      end 
    4949 
    50       def extract_record(record_or_hash) 
    51         record_or_hash.is_a?(Hash) ? record_or_hash[:id] : record_or_hash 
     50      def build_named_route_call(records, singular_or_plural, options = {}) 
     51        records = Array.new([extract_record(records)]) unless records.is_a?(Array) 
     52        base_segment = "#{RecordIdentifier.send("#{singular_or_plural.to_s}_class_name", records.pop)}_" 
     53         
     54        method_root = records.reverse.inject(base_segment) do |string, name| 
     55          segment = "#{RecordIdentifier.send("singular_class_name", name)}_" 
     56          segment << string 
     57        end 
     58 
     59        action_prefix(options) + method_root + routing_type(options) 
    5260      end 
     61 
     62      def extract_record(record_or_hash_or_array) 
     63        case record_or_hash_or_array 
     64        when Array: record_or_hash_or_array.last 
     65        when Hash: record_or_hash_or_array[:id] 
     66        else record_or_hash_or_array 
     67        end 
     68      end 
    5369  end 
    5470end 
  • actionpack/lib/action_view/helpers/form_helper.rb

    old new  
    163163        case record_or_name 
    164164        when String, Symbol 
    165165          object_name = record_or_name 
     166        when Array 
     167          object = record_or_name.last 
     168          object_name = ActionController::RecordIdentifier.singular_class_name(object) 
     169          apply_form_for_options!(object, options, *record_or_name) 
     170          args.unshift object 
    166171        else 
    167           object      = record_or_name 
    168           object_name = ActionController::RecordIdentifier.singular_class_name(record_or_name
     172          object = record_or_name 
     173          object_name = ActionController::RecordIdentifier.singular_class_name(object
    169174          apply_form_for_options!(object, options) 
    170175          args.unshift object 
    171176        end 
     
    175180        concat('</form>', proc.binding) 
    176181      end 
    177182       
    178       def apply_form_for_options!(object, options) #:nodoc: 
     183      def apply_form_for_options!(object, options, *nested_objects) #:nodoc: 
    179184        html_options = if object.respond_to?(:new_record?) && object.new_record? 
    180185          { :class  => dom_class(object, :new),  :id => dom_id(object), :method => :post } 
    181186        else 
     
    184189         
    185190        options[:html] ||= {} 
    186191        options[:html].reverse_merge!(html_options) 
    187  
    188         options[:url] ||= polymorphic_path(object) 
     192        options[:url] ||= polymorphic_path(object, *nested_objects) 
    189193      end 
    190194 
    191195      # Creates a scope around a specific model object like form_for, but doesn't create the form tags themselves. This makes