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

Changeset 8741

Show
Ignore:
Timestamp:
01/27/08 01:18:47 (10 months ago)
Author:
nzkoz
Message:

Add documentation for polymorphic URL helpers, make API consistent for polymorphic_path and polymorphic_url.

Closes #10883 [mislav] Closes #8782 [gbuesing] Closes #8720 [gbuesing]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/lib/action_controller/polymorphic_routes.rb

    r7719 r8741  
    11module ActionController 
     2  # Polymorphic URL helpers are methods for smart resolution to a named route call when 
     3  # given an ActiveRecord model instance. They are to be used in combination with 
     4  # ActionController::Resources. 
     5  # 
     6  # These methods are useful when you want to generate correct URL or path to a RESTful 
     7  # resource without having to know the exact type of the record in question. 
     8  # 
     9  # Nested resources and/or namespaces are also supported, as illustrated in the example: 
     10  # 
     11  #   polymorphic_url([:admin, @article, @comment]) 
     12  #   #-> results in: 
     13  #   admin_article_comment_url(@article, @comment) 
     14  # 
     15  # == Usage within the framework 
     16  # 
     17  # Polymorphic URL helpers are used in a number of places throughout the Rails framework: 
     18  # 
     19  # * <tt>url_for</tt>, so you can use it with a record as the argument, e.g. 
     20  #   <tt>url_for(@article)</tt>; 
     21  # * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write 
     22  #   <tt>form_for(@article)</tt> without having to specify :url parameter for the form 
     23  #   action; 
     24  # * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write 
     25  #   <tt>redirect_to(post)</tt> in your controllers; 
     26  # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs 
     27  #   for feed entries. 
     28  # 
     29  # == Prefixed polymorphic helpers 
     30  # 
     31  # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a 
     32  # number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt> 
     33  # in options. Those are: 
     34  # 
     35  # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt> 
     36  # * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt> 
     37  # * <tt>formatted_polymorphic_url</tt>, <tt>formatted_polymorphic_path</tt> 
     38  # 
     39  # Example usage: 
     40  # 
     41  #   edit_polymorphic_path(@post) 
     42  #   #=> /posts/1/edit 
     43  # 
     44  #   formatted_polymorphic_path([@post, :pdf]) 
     45  #   #=> /posts/1.pdf 
    246  module PolymorphicRoutes 
     47    # Constructs a call to a named RESTful route for the given record and returns the 
     48    # resulting URL string. For example: 
     49    # 
     50    #   polymorphic_url(post) 
     51    #   # calls post_url(post) #=> "http://example.com/posts/1" 
     52    # 
     53    # ==== Options 
     54    # * <tt>:action</tt> -- specifies the action prefix for the named route: 
     55    #   <tt>:new</tt>, <tt>:edit</tt> or <tt>:formatted</tt>. Default is no prefix. 
     56    # * <tt>:routing_type</tt> -- <tt>:path</tt> or <tt>:url</tt> (default <tt>:url</tt>). 
     57    # 
     58    # ==== Examples 
     59    # 
     60    #   # an Article record 
     61    #   polymorphic_url(record)  #->  article_url(record) 
     62    # 
     63    #   # a Comment record 
     64    #   polymorphic_url(record)  #->  comment_url(record) 
     65    # 
     66    #   # it recognizes new records and maps to the collection 
     67    #   record = Comment.new 
     68    #   polymorphic_url(record)  #->  comments_url() 
     69    # 
    370    def polymorphic_url(record_or_hash_or_array, options = {}) 
    4       record = extract_record(record_or_hash_or_array) 
    5  
     71      record    = extract_record(record_or_hash_or_array) 
     72      format    = (options[:action].to_s == "formatted" and record_or_hash_or_array.pop) 
    673      namespace = extract_namespace(record_or_hash_or_array) 
    774       
     
    1279      end 
    1380 
     81      args << format if format 
     82 
    1483      inflection = 
    1584        case 
    16         when options[:action] == "new" 
     85        when options[:action].to_s == "new" 
    1786          args.pop 
    1887          :singular 
     
    2897    end 
    2998 
    30     def polymorphic_path(record_or_hash_or_array) 
    31       polymorphic_url(record_or_hash_or_array, :routing_type => :path) 
     99    # Returns the path component of a URL for the given record. It uses 
     100    # <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>. 
     101    def polymorphic_path(record_or_hash_or_array, options = {}) 
     102      options[:routing_type] = :path 
     103      polymorphic_url(record_or_hash_or_array, options) 
    32104    end 
    33105 
     
    44116    end 
    45117 
    46  
    47118    private 
    48119      def action_prefix(options) 
     
    51122 
    52123      def routing_type(options) 
    53         "#{options[:routing_type] || "url"}" 
     124        options[:routing_type] || :url 
    54125      end 
    55126 
    56127      def build_named_route_call(records, namespace, inflection, options = {}) 
    57         records = Array.new([extract_record(records)]) unless records.is_a?(Array)         
    58         base_segment = "#{RecordIdentifier.send!("#{inflection}_class_name", records.pop)}_" 
    59  
    60         method_root = records.reverse.inject(base_segment) do |string, name| 
    61           segment = "#{RecordIdentifier.send!("singular_class_name", name)}_" 
    62           segment << string 
     128        unless records.is_a?(Array) 
     129          record = extract_record(records) 
     130          route  = '' 
     131        else 
     132          record = records.pop 
     133          route = records.inject("") do |string, parent| 
     134            string << "#{RecordIdentifier.send!("singular_class_name", parent)}_" 
     135          end 
    63136        end 
    64137 
    65         action_prefix(options) + namespace + method_root + routing_type(options) 
     138        route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_" 
     139 
     140        action_prefix(options) + namespace + route + routing_type(options).to_s 
    66141      end 
    67142 
     
    79154            record_or_hash_or_array.delete_if do |record_or_namespace| 
    80155              if record_or_namespace.is_a?(String) || record_or_namespace.is_a?(Symbol) 
    81                 namespace << "#{record_or_namespace.to_s}_" 
     156                namespace << "#{record_or_namespace}_" 
    82157              end 
    83158            end 
  • trunk/actionpack/test/controller/polymorphic_routes_test.rb

    r8564 r8741  
    66  def new_record?; @id.nil? end 
    77  def name 
    8     @id.nil? ? 'new post' : "post ##{@id}" 
     8    model = self.class.name.downcase 
     9    @id.nil? ? "new #{model}" : "#{model} ##{@id}" 
    910  end 
    1011end 
    1112 
    12 class Comment 
    13   attr_reader :id 
     13class Comment < Article 
    1414  def post_id; 1 end 
    15   def save; @id = 1 end 
    16   def new_record?; @id.nil? end 
    17   def name 
    18     @id.nil? ? 'new comment' : "comment ##{@id}" 
     15end 
     16 
     17class Tag < Article 
     18  def comment_id; 1 end 
     19end 
     20 
     21# TODO: test nested models 
     22class Comment::Nested < Comment; end 
     23 
     24uses_mocha 'polymorphic URL helpers' do 
     25  class PolymorphicRoutesTest < Test::Unit::TestCase 
     26 
     27    include ActionController::PolymorphicRoutes 
     28 
     29    def setup 
     30      @article = Article.new 
     31      @comment = Comment.new 
     32    end 
     33   
     34    def test_with_record 
     35      @article.save 
     36      expects(:article_url).with(@article) 
     37      polymorphic_url(@article) 
     38    end 
     39 
     40    def test_with_new_record 
     41      expects(:articles_url).with() 
     42      @article.expects(:new_record?).returns(true) 
     43      polymorphic_url(@article) 
     44    end 
     45 
     46    def test_with_record_and_action 
     47      expects(:new_article_url).with() 
     48      @article.expects(:new_record?).never 
     49      polymorphic_url(@article, :action => 'new') 
     50    end 
     51 
     52    def test_url_helper_prefixed_with_new 
     53      expects(:new_article_url).with() 
     54      new_polymorphic_url(@article) 
     55    end 
     56 
     57    def test_url_helper_prefixed_with_edit 
     58      @article.save 
     59      expects(:edit_article_url).with(@article) 
     60      edit_polymorphic_url(@article) 
     61    end 
     62 
     63    def test_formatted_url_helper 
     64      expects(:formatted_article_url).with(@article, :pdf) 
     65      formatted_polymorphic_url([@article, :pdf]) 
     66    end 
     67 
     68    # TODO: should this work? 
     69    def xtest_format_option 
     70      @article.save 
     71      expects(:article_url).with(@article, :format => :pdf) 
     72      polymorphic_url(@article, :format => :pdf) 
     73    end 
     74 
     75    def test_with_nested 
     76      @comment.save 
     77      expects(:article_comment_url).with(@article, @comment) 
     78      polymorphic_url([@article, @comment]) 
     79    end 
     80 
     81    def test_with_nested_unsaved 
     82      expects(:article_comments_url).with(@article) 
     83      polymorphic_url([@article, @comment]) 
     84    end 
     85 
     86    def test_new_with_array_and_namespace 
     87      expects(:new_admin_article_url).with() 
     88      polymorphic_url([:admin, @article], :action => 'new') 
     89    end 
     90 
     91    def test_unsaved_with_array_and_namespace 
     92      expects(:admin_articles_url).with() 
     93      polymorphic_url([:admin, @article]) 
     94    end 
     95 
     96    def test_nested_unsaved_with_array_and_namespace 
     97      @article.save 
     98      expects(:admin_article_url).with(@article) 
     99      polymorphic_url([:admin, @article]) 
     100      expects(:admin_article_comments_url).with(@article) 
     101      polymorphic_url([:admin, @article, @comment]) 
     102    end 
     103 
     104    def test_nested_with_array_and_namespace 
     105      @comment.save 
     106      expects(:admin_article_comment_url).with(@article, @comment) 
     107      polymorphic_url([:admin, @article, @comment]) 
     108 
     109      # a ridiculously long named route tests correct ordering of namespaces and nesting: 
     110      @tag = Tag.new 
     111      @tag.save 
     112      expects(:site_admin_article_comment_tag_url).with(@article, @comment, @tag) 
     113      polymorphic_url([:site, :admin, @article, @comment, @tag]) 
     114    end 
     115 
     116    # TODO: Needs to be updated to correctly know about whether the object is in a hash or not 
     117    def xtest_with_hash 
     118      expects(:article_url).with(@article) 
     119      @article.save 
     120      polymorphic_url(:id => @article) 
     121    end 
     122 
     123    def test_polymorphic_path_accepts_options 
     124      expects(:new_article_path).with() 
     125      polymorphic_path(@article, :action => :new) 
     126    end 
     127 
    19128  end 
    20129end 
    21  
    22 class Comment::Nested < Comment; end 
    23  
    24 class Test::Unit::TestCase 
    25   protected 
    26   def articles_url 
    27     'http://www.example.com/articles' 
    28   end 
    29   alias_method :new_article_url, :articles_url 
    30    
    31   def article_url(article) 
    32     "http://www.example.com/articles/#{article.id}" 
    33   end 
    34  
    35   def article_comments_url(article) 
    36     "http://www.example.com/articles/#{article.id}/comments" 
    37   end 
    38    
    39   def article_comment_url(article, comment) 
    40     "http://www.example.com/articles/#{article.id}/comments/#{comment.id}" 
    41   end 
    42    
    43   def admin_articles_url 
    44     "http://www.example.com/admin/articles" 
    45   end 
    46   alias_method :new_admin_article_url, :admin_articles_url 
    47    
    48   def admin_article_url(article) 
    49     "http://www.example.com/admin/articles/#{article.id}" 
    50   end 
    51    
    52   def admin_article_comments_url(article) 
    53     "http://www.example.com/admin/articles/#{article.id}/comments" 
    54   end 
    55    
    56   def admin_article_comment_url(article, comment) 
    57     "http://www.example.com/admin/test/articles/#{article.id}/comments/#{comment.id}" 
    58   end 
    59 end 
    60  
    61  
    62 class PolymorphicRoutesTest < Test::Unit::TestCase 
    63   include ActionController::PolymorphicRoutes 
    64  
    65   def setup 
    66     @article = Article.new 
    67     @comment = Comment.new 
    68   end 
    69    
    70   def test_with_record 
    71     assert_equal(articles_url, polymorphic_url(@article, :action => 'new')) 
    72     assert_equal(articles_url, polymorphic_url(@article)) 
    73     @article.save 
    74     assert_equal(article_url(@article), polymorphic_url(@article)) 
    75   end 
    76    
    77   # TODO: Needs to be updated to correctly know about whether the object is in a hash or not 
    78   def xtest_with_hash 
    79     @article.save 
    80     assert_equal(article_url(@article), polymorphic_url(:id => @article)) 
    81   end 
    82  
    83   def test_with_array 
    84     assert_equal(article_comments_url(@article), polymorphic_url([@article, @comment])) 
    85     @comment.save 
    86     assert_equal(article_comment_url(@article, @comment), polymorphic_url([@article, @comment])) 
    87   end   
    88    
    89   def test_with_array_and_namespace 
    90     assert_equal(admin_articles_url, polymorphic_url([:admin, @article], :action => 'new')) 
    91     assert_equal(admin_articles_url, polymorphic_url([:admin, @article])) 
    92     @article.save 
    93     assert_equal(admin_article_url(@article), polymorphic_url([:admin, @article])) 
    94     assert_equal(admin_article_comments_url(@article), polymorphic_url([:admin, @article, @comment])) 
    95     @comment.save 
    96     assert_equal(admin_article_comment_url(@article, @comment), polymorphic_url([:admin, @article, @comment])) 
    97   end 
    98 end