diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index acb0b570abe6f..683c0818909b2 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *2.1.1 (next release)* +* Fix polymorphic_url with singleton resources. #461 [Tammer Saleh] + * Deprecate ActionView::Base.erb_variable. Use the concat helper method instead of appending to it directly. [Jeremy Kemper] * Fixed Request#remote_ip to only raise hell if the HTTP_CLIENT_IP and HTTP_X_FORWARDED_FOR doesn't match (not just if they're both present) [Mark Imbriaco, Bradford Folkens] diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb index 509fa6a08e920..7c30bf0778493 100644 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/actionpack/lib/action_controller/polymorphic_routes.rb @@ -48,6 +48,9 @@ module PolymorphicRoutes # # # calls post_url(post) # polymorphic_url(post) # => "http://example.com/posts/1" + # polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1" + # polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1" + # polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1" # # ==== Options # @@ -83,8 +86,6 @@ def polymorphic_url(record_or_hash_or_array, options = {}) else [ record_or_hash_or_array ] end - args << format if format - inflection = case when options[:action].to_s == "new" @@ -96,6 +97,9 @@ def polymorphic_url(record_or_hash_or_array, options = {}) else :singular end + + args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)} + args << format if format named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options) send!(named_route, *args) @@ -136,11 +140,19 @@ def build_named_route_call(records, namespace, inflection, options = {}) else record = records.pop route = records.inject("") do |string, parent| - string << "#{RecordIdentifier.send!("singular_class_name", parent)}_" + if parent.is_a?(Symbol) || parent.is_a?(String) + string << "#{parent}_" + else + string << "#{RecordIdentifier.send!("singular_class_name", parent)}_" + end end end - route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_" + if record.is_a?(Symbol) || record.is_a?(String) + route << "#{record}_" + else + route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_" + end action_prefix(options) + namespace + route + routing_type(options).to_s end @@ -163,16 +175,17 @@ def extract_format(record_or_hash_or_array, options) end end + # Remove the first symbols from the array and return the url prefix + # implied by those symbols. def extract_namespace(record_or_hash_or_array) - returning "" do |namespace| - if record_or_hash_or_array.is_a?(Array) - record_or_hash_or_array.delete_if do |record_or_namespace| - if record_or_namespace.is_a?(String) || record_or_namespace.is_a?(Symbol) - namespace << "#{record_or_namespace}_" - end - end - end + return "" unless record_or_hash_or_array.is_a?(Array) + + namespace_keys = [] + while (key = record_or_hash_or_array.first) && key.is_a?(String) || key.is_a?(Symbol) + namespace_keys << record_or_hash_or_array.shift end + + namespace_keys.map {|k| "#{k}_"}.join end end end diff --git a/actionpack/test/controller/polymorphic_routes_test.rb b/actionpack/test/controller/polymorphic_routes_test.rb index 4ec0d3cd4e4c2..3f52526f08415 100644 --- a/actionpack/test/controller/polymorphic_routes_test.rb +++ b/actionpack/test/controller/polymorphic_routes_test.rb @@ -118,6 +118,39 @@ def test_nested_with_array_and_namespace polymorphic_url([:site, :admin, @article, @response, @tag]) end + def test_nesting_with_array_ending_in_singleton_resource + expects(:article_response_url).with(@article) + polymorphic_url([@article, :response]) + end + + def test_nesting_with_array_containing_singleton_resource + @tag = Tag.new + @tag.save + expects(:article_response_tag_url).with(@article, @tag) + polymorphic_url([@article, :response, @tag]) + end + + def test_nesting_with_array_containing_namespace_and_singleton_resource + @tag = Tag.new + @tag.save + expects(:admin_article_response_tag_url).with(@article, @tag) + polymorphic_url([:admin, @article, :response, @tag]) + end + + def test_nesting_with_array_containing_singleton_resource_and_format + @tag = Tag.new + @tag.save + expects(:formatted_article_response_tag_url).with(@article, @tag, :pdf) + formatted_polymorphic_url([@article, :response, @tag, :pdf]) + end + + def test_nesting_with_array_containing_singleton_resource_and_format_option + @tag = Tag.new + @tag.save + expects(:article_response_tag_url).with(@article, @tag, :pdf) + polymorphic_url([@article, :response, @tag], :format => :pdf) + end + # TODO: Needs to be updated to correctly know about whether the object is in a hash or not def xtest_with_hash expects(:article_url).with(@article)