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

Changeset 6951

Show
Ignore:
Timestamp:
06/05/07 19:10:59 (2 years ago)
Author:
bitsweat
Message:

Resources: url_for([parent, child]) generates /parents/1/children/2 for the nested resource. Likewise with the other simply helpful methods like form_for and link_to. Closes #6432.

Files:

Legend:

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

    r6950 r6951  
    11*SVN* 
     2 
     3* Resources: url_for([parent, child]) generates /parents/1/children/2 for the nested resource. Likewise with the other simply helpful methods like form_for and link_to.  #6432 [mhw, Jonathan Vaught] 
    24 
    35* Assume html format when rendering partials in RJS. #8076 [Rick] 
  • trunk/actionpack/lib/action_controller/polymorphic_routes.rb

    r6751 r6951  
    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 
    6       case 
    7       when options[:action] == "new" 
    8         send( 
    9           action_prefix(options) + RecordIdentifier.singular_class_name(record) + routing_type(options) 
    10         ) 
     6      args = [] 
     7      inflection = 
     8        case 
     9        when options[:action] == "new" 
     10          :singular 
     11        when record.respond_to?(:new_record?) && record.new_record? 
     12          :plural 
     13        else 
     14          args = [record_or_hash_or_array] 
     15          :singular 
     16        end 
    1117 
    12       when record.respond_to?(:new_record?) && record.new_record? 
    13         send( 
    14           action_prefix(options) + RecordIdentifier.plural_class_name(record) + routing_type(options) 
    15         ) 
    16  
    17       else 
    18         send( 
    19           action_prefix(options) + RecordIdentifier.singular_class_name(record) + routing_type(options), record_or_hash 
    20         ) 
    21       end 
     18      named_route = build_named_route_call(record_or_hash_or_array, inflection, options) 
     19      send(named_route, *args) 
    2220    end 
    2321 
    24     def polymorphic_path(record_or_hash
    25       polymorphic_url(record_or_hash, :routing_type => :path) 
     22    def polymorphic_path(record_or_hash_or_array
     23      polymorphic_url(record_or_hash_or_array, :routing_type => :path) 
    2624    end 
    2725 
    28     %w( edit new formatted ).each do |action| 
     26    %w(edit new formatted).each do |action| 
    2927      module_eval <<-EOT, __FILE__, __LINE__ 
    3028        def #{action}_polymorphic_url(record_or_hash) 
     
    4543 
    4644      def routing_type(options) 
    47         "_#{options[:routing_type] || "url"}" 
     45        "#{options[:routing_type] || "url"}" 
    4846      end 
    4947 
    50       def extract_record(record_or_hash) 
    51         record_or_hash.is_a?(Hash) ? record_or_hash[:id] : record_or_hash 
     48      def build_named_route_call(records, inflection, options = {}) 
     49        records = Array.new([extract_record(records)]) unless records.is_a?(Array) 
     50        base_segment = "#{RecordIdentifier.send("#{inflection}_class_name", records.pop)}_" 
     51 
     52        method_root = records.reverse.inject(base_segment) do |string, name| 
     53          segment = "#{RecordIdentifier.send("singular_class_name", name)}_" 
     54          segment << string 
     55        end 
     56 
     57        action_prefix(options) + method_root + routing_type(options) 
     58      end 
     59 
     60      def extract_record(record_or_hash_or_array) 
     61        case record_or_hash_or_array 
     62          when Array: record_or_hash_or_array.last 
     63          when Hash:  record_or_hash_or_array[:id] 
     64          else        record_or_hash_or_array 
     65        end 
    5266      end 
    5367  end 
  • trunk/actionpack/lib/action_controller/record_identifier.rb

    r6731 r6951  
    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. 
  • trunk/actionpack/lib/action_view/helpers/form_helper.rb

    r6830 r6951  
    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 
     
    175180        concat('</form>', proc.binding) 
    176181      end 
    177        
    178       def apply_form_for_options!(object, options) #:nodoc: 
    179         html_options = if object.respond_to?(:new_record?) && object.new_record? 
    180           { :class  => dom_class(object, :new),  :id => dom_id(object), :method => :post } 
    181         else 
    182           { :class  => dom_class(object, :edit), :id => dom_id(object, :edit), :method => :put } 
    183         end 
    184          
     182 
     183      def apply_form_for_options!(object, options, *nested_objects) #:nodoc: 
     184        html_options = 
     185          if object.respond_to?(:new_record?) && object.new_record? 
     186            { :class  => dom_class(object, :new),  :id => dom_id(object), :method => :post } 
     187          else 
     188            { :class  => dom_class(object, :edit), :id => dom_id(object, :edit), :method => :put } 
     189          end 
     190 
    185191        options[:html] ||= {} 
    186192        options[:html].reverse_merge!(html_options) 
    187  
    188         options[:url] ||= polymorphic_path(object) 
     193        options[:url] ||= polymorphic_path(object, *nested_objects) 
    189194      end 
    190195 
  • trunk/actionpack/test/template/form_helper_test.rb

    r6941 r6951  
    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 
     29 
     30class Comment::Nested < Comment; end 
     31 
    1932 
    2033class FormHelperTest < Test::Unit::TestCase 
     
    2942  def setup 
    3043    @post = Post.new 
     44    @comment = Comment.new 
    3145    def @post.errors()  
    3246      Class.new{  
     
    580594  end 
    581595 
     596  def test_form_for_with_existing_object_in_list 
     597    @post.new_record = false 
     598    @comment.save 
     599    _erbout = '' 
     600    form_for([@post, @comment]) {} 
     601 
     602    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>) 
     603    assert_dom_equal expected, _erbout 
     604  end 
     605 
     606  def test_form_for_with_new_object_in_list 
     607    @post.new_record = false 
     608    _erbout = '' 
     609    form_for([@post, @comment]) {} 
     610 
     611    expected = %(<form action="#{comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>) 
     612    assert_dom_equal expected, _erbout 
     613  end 
     614 
    582615  def test_form_for_with_existing_object_and_custom_url 
    583616    _erbout = '' 
     
    601634 
    602635  protected 
    603     def polymorphic_path(record) 
    604       if record.new_record? 
    605         "/posts" 
     636    def comments_path(post) 
     637      "/posts/#{post.id}/comments" 
     638    end 
     639 
     640    def comment_path(post, comment) 
     641      "/posts/#{post.id}/comments/#{comment.id}" 
     642    end 
     643 
     644    def polymorphic_path(object, *nested_objects) 
     645      if nested_objects.empty? 
     646        if object.new_record? 
     647          "/posts" 
     648        else 
     649          "/posts/#{object.id}" 
     650        end 
    606651      else 
    607         "/posts/#{record.id}" 
     652        if object.new_record? 
     653          "/posts/123/comments" 
     654        else 
     655          "/posts/123/comments/#{object.id}" 
     656        end 
    608657      end 
    609658    end 
  • trunk/actionpack/test/template/url_helper_test.rb

    r6942 r6951  
    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 new_record? 
     386    @new_record 
     387  end 
     388 
     389  def to_s 
     390    id.to_s 
     391  end 
     392end 
     393 
    378394class PolymorphicControllerTest < Test::Unit::TestCase 
    379395  class WorkshopsController < ActionController::Base 
     
    395411  end 
    396412 
     413  class SessionsController < ActionController::Base 
     414    self.view_paths = ["#{File.dirname(__FILE__)}/../fixtures/"] 
     415 
     416    def self.controller_path; 'sessions' end 
     417 
     418    def index 
     419      @workshop = Workshop.new(params[:workshop_id], false) 
     420      @session = Session.new(1, true) 
     421      render :inline => "<%= url_for([@workshop, @session]) %>\n<%= link_to('Session', [@workshop, @session]) %>" 
     422    end 
     423 
     424    def show 
     425      @workshop = Workshop.new(params[:workshop_id], false) 
     426      @session = Session.new(params[:id], false) 
     427      render :inline => "<%= url_for([@workshop, @session]) %>\n<%= link_to('Session', [@workshop, @session]) %>" 
     428    end 
     429 
     430    def rescue_action(e) raise e end 
     431  end 
     432 
    397433  include ActionView::Helpers::UrlHelper 
    398434 
     
    400436    @request    = ActionController::TestRequest.new 
    401437    @response   = ActionController::TestResponse.new 
     438  end 
     439 
     440  def test_new_resource 
    402441    @controller = WorkshopsController.new 
    403   end 
    404  
    405   def test_new_resource 
     442 
    406443    with_restful_routing do 
    407444      get :index 
     
    411448 
    412449  def test_existing_resource 
     450    @controller = WorkshopsController.new 
     451 
    413452    with_restful_routing do 
    414453      get :show, :id => 1 
    415454      assert_equal "/workshops/1\n<a href=\"/workshops/1\">Workshop</a>", @response.body 
     455    end 
     456  end 
     457 
     458  def test_new_nested_resource 
     459    @controller = SessionsController.new 
     460 
     461    with_restful_routing do 
     462      get :index, :workshop_id => 1 
     463      assert_equal "/workshops/1/sessions\n<a href=\"/workshops/1/sessions\">Session</a>", @response.body 
     464    end 
     465  end 
     466 
     467  def test_existing_nested_resource 
     468    @controller = SessionsController.new 
     469 
     470    with_restful_routing do 
     471      get :show, :workshop_id => 1, :id => 1 
     472      assert_equal "/workshops/1/sessions/1\n<a href=\"/workshops/1/sessions/1\">Session</a>", @response.body 
    416473    end 
    417474  end 
     
    421478      with_routing do |set| 
    422479        set.draw do |map| 
    423           map.resources :workshops 
     480          map.resources :workshops do |w| 
     481            w.resources :sessions 
     482          end 
    424483        end 
    425484        yield