diff options
Diffstat (limited to 'actionpack/lib')
-rw-r--r-- | actionpack/lib/action_controller.rb | 1 | ||||
-rw-r--r-- | actionpack/lib/action_controller/base.rb | 1 | ||||
-rw-r--r-- | actionpack/lib/action_controller/polymorphic_routes.rb | 183 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing.rb | 4 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing/polymorphic_routes.rb | 186 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing/url_for.rb | 1 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/record_identification_helper.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/test_case.rb | 2 |
8 files changed, 191 insertions, 189 deletions
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 1bd4572a47..ca0e5d6ff6 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -6,7 +6,6 @@ module ActionController autoload :Base autoload :Caching - autoload :PolymorphicRoutes autoload :Metal autoload :Middleware diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index cfe6b30add..1c6896d362 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -28,7 +28,6 @@ module ActionController SessionManagement, Caching, MimeResponds, - PolymorphicRoutes, ImplicitRender, Cookies, diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb deleted file mode 100644 index b4837c610a..0000000000 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ /dev/null @@ -1,183 +0,0 @@ -module ActionController - # Polymorphic URL helpers are methods for smart resolution to a named route call when - # given an Active Record model instance. They are to be used in combination with - # ActionController::Resources. - # - # These methods are useful when you want to generate correct URL or path to a RESTful - # resource without having to know the exact type of the record in question. - # - # Nested resources and/or namespaces are also supported, as illustrated in the example: - # - # polymorphic_url([:admin, @article, @comment]) - # - # results in: - # - # admin_article_comment_url(@article, @comment) - # - # == Usage within the framework - # - # Polymorphic URL helpers are used in a number of places throughout the Rails framework: - # - # * <tt>url_for</tt>, so you can use it with a record as the argument, e.g. - # <tt>url_for(@article)</tt>; - # * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write - # <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form - # action; - # * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write - # <tt>redirect_to(post)</tt> in your controllers; - # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs - # for feed entries. - # - # == Prefixed polymorphic helpers - # - # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a - # number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt> - # in options. Those are: - # - # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt> - # * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt> - # - # Example usage: - # - # edit_polymorphic_path(@post) # => "/posts/1/edit" - # polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf" - module PolymorphicRoutes - # Constructs a call to a named RESTful route for the given record and returns the - # resulting URL string. For example: - # - # # 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" - # polymorphic_url(Comment) # => "http://example.com/comments" - # - # ==== Options - # - # * <tt>:action</tt> - Specifies the action prefix for the named route: - # <tt>:new</tt> or <tt>:edit</tt>. Default is no prefix. - # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>. - # Default is <tt>:url</tt>. - # - # ==== Examples - # - # # an Article record - # polymorphic_url(record) # same as article_url(record) - # - # # a Comment record - # polymorphic_url(record) # same as comment_url(record) - # - # # it recognizes new records and maps to the collection - # record = Comment.new - # polymorphic_url(record) # same as comments_url() - # - # # the class of a record will also map to the collection - # polymorphic_url(Comment) # same as comments_url() - # - def polymorphic_url(record_or_hash_or_array, options = {}) - if record_or_hash_or_array.kind_of?(Array) - record_or_hash_or_array = record_or_hash_or_array.compact - record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1 - end - - record = extract_record(record_or_hash_or_array) - record = record.to_model if record.respond_to?(:to_model) - - args = case record_or_hash_or_array - when Hash; [ record_or_hash_or_array ] - when Array; record_or_hash_or_array.dup - else [ record_or_hash_or_array ] - end - - inflection = if options[:action].to_s == "new" - args.pop - :singular - elsif (record.respond_to?(:persisted?) && !record.persisted?) - args.pop - :plural - elsif record.is_a?(Class) - args.pop - :plural - else - :singular - end - - args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)} - named_route = build_named_route_call(record_or_hash_or_array, inflection, options) - - url_options = options.except(:action, :routing_type) - unless url_options.empty? - args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options - end - - send(named_route, *args) - end - - # Returns the path component of a URL for the given record. It uses - # <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>. - def polymorphic_path(record_or_hash_or_array, options = {}) - polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path)) - end - - %w(edit new).each do |action| - module_eval <<-EOT, __FILE__, __LINE__ + 1 - def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {}) - polymorphic_url( # polymorphic_url( - record_or_hash, # record_or_hash, - options.merge(:action => "#{action}")) # options.merge(:action => "edit")) - end # end - # - def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {}) - polymorphic_url( # polymorphic_url( - record_or_hash, # record_or_hash, - options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path)) - end # end - EOT - end - - private - def action_prefix(options) - options[:action] ? "#{options[:action]}_" : '' - end - - def routing_type(options) - options[:routing_type] || :url - end - - def build_named_route_call(records, inflection, options = {}) - unless records.is_a?(Array) - record = extract_record(records) - route = '' - else - record = records.pop - route = records.inject("") do |string, parent| - if parent.is_a?(Symbol) || parent.is_a?(String) - string << "#{parent}_" - else - string << RecordIdentifier.plural_class_name(parent).singularize - string << "_" - end - end - end - - if record.is_a?(Symbol) || record.is_a?(String) - route << "#{record}_" - else - route << RecordIdentifier.plural_class_name(record) - route = route.singularize if inflection == :singular - route << "_" - route << "index_" if RecordIdentifier.uncountable?(record) && inflection == :plural - end - - action_prefix(options) + route + routing_type(options).to_s - end - - def extract_record(record_or_hash_or_array) - case record_or_hash_or_array - when Array; record_or_hash_or_array.last - when Hash; record_or_hash_or_array[:id] - else record_or_hash_or_array - end - end - end -end diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index da62b14f9b..b7e09b99d1 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -1,6 +1,5 @@ require 'active_support/core_ext/object/to_param' require 'active_support/core_ext/regexp' -require 'action_controller/polymorphic_routes' module ActionDispatch # = Routing @@ -217,13 +216,14 @@ module ActionDispatch autoload :Route, 'action_dispatch/routing/route' autoload :RouteSet, 'action_dispatch/routing/route_set' autoload :UrlFor, 'action_dispatch/routing/url_for' + autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes' SEPARATORS = %w( / . ? ) #:nodoc: HTTP_METHODS = [:get, :head, :post, :put, :delete, :options] #:nodoc: # A helper module to hold URL related helpers. module Helpers #:nodoc: - include ActionController::PolymorphicRoutes + include PolymorphicRoutes end end end diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb new file mode 100644 index 0000000000..18ea82c478 --- /dev/null +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -0,0 +1,186 @@ +module ActionDispatch + module Routing + # Polymorphic URL helpers are methods for smart resolution to a named route call when + # given an Active Record model instance. They are to be used in combination with + # ActionController::Resources. + # + # These methods are useful when you want to generate correct URL or path to a RESTful + # resource without having to know the exact type of the record in question. + # + # Nested resources and/or namespaces are also supported, as illustrated in the example: + # + # polymorphic_url([:admin, @article, @comment]) + # + # results in: + # + # admin_article_comment_url(@article, @comment) + # + # == Usage within the framework + # + # Polymorphic URL helpers are used in a number of places throughout the Rails framework: + # + # * <tt>url_for</tt>, so you can use it with a record as the argument, e.g. + # <tt>url_for(@article)</tt>; + # * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write + # <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form + # action; + # * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write + # <tt>redirect_to(post)</tt> in your controllers; + # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs + # for feed entries. + # + # == Prefixed polymorphic helpers + # + # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a + # number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt> + # in options. Those are: + # + # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt> + # * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt> + # + # Example usage: + # + # edit_polymorphic_path(@post) # => "/posts/1/edit" + # polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf" + module PolymorphicRoutes + # Constructs a call to a named RESTful route for the given record and returns the + # resulting URL string. For example: + # + # # 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" + # polymorphic_url(Comment) # => "http://example.com/comments" + # + # ==== Options + # + # * <tt>:action</tt> - Specifies the action prefix for the named route: + # <tt>:new</tt> or <tt>:edit</tt>. Default is no prefix. + # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>. + # Default is <tt>:url</tt>. + # + # ==== Examples + # + # # an Article record + # polymorphic_url(record) # same as article_url(record) + # + # # a Comment record + # polymorphic_url(record) # same as comment_url(record) + # + # # it recognizes new records and maps to the collection + # record = Comment.new + # polymorphic_url(record) # same as comments_url() + # + # # the class of a record will also map to the collection + # polymorphic_url(Comment) # same as comments_url() + # + def polymorphic_url(record_or_hash_or_array, options = {}) + if record_or_hash_or_array.kind_of?(Array) + record_or_hash_or_array = record_or_hash_or_array.compact + record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1 + end + + record = extract_record(record_or_hash_or_array) + record = record.to_model if record.respond_to?(:to_model) + + args = case record_or_hash_or_array + when Hash; [ record_or_hash_or_array ] + when Array; record_or_hash_or_array.dup + else [ record_or_hash_or_array ] + end + + inflection = if options[:action].to_s == "new" + args.pop + :singular + elsif (record.respond_to?(:persisted?) && !record.persisted?) + args.pop + :plural + elsif record.is_a?(Class) + args.pop + :plural + else + :singular + end + + args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)} + named_route = build_named_route_call(record_or_hash_or_array, inflection, options) + + url_options = options.except(:action, :routing_type) + unless url_options.empty? + args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options + end + + send(named_route, *args) + end + + # Returns the path component of a URL for the given record. It uses + # <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>. + def polymorphic_path(record_or_hash_or_array, options = {}) + polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path)) + end + + %w(edit new).each do |action| + module_eval <<-EOT, __FILE__, __LINE__ + 1 + def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {}) + polymorphic_url( # polymorphic_url( + record_or_hash, # record_or_hash, + options.merge(:action => "#{action}")) # options.merge(:action => "edit")) + end # end + # + def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {}) + polymorphic_url( # polymorphic_url( + record_or_hash, # record_or_hash, + options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path)) + end # end + EOT + end + + private + def action_prefix(options) + options[:action] ? "#{options[:action]}_" : '' + end + + def routing_type(options) + options[:routing_type] || :url + end + + def build_named_route_call(records, inflection, options = {}) + unless records.is_a?(Array) + record = extract_record(records) + route = '' + else + record = records.pop + route = records.inject("") do |string, parent| + if parent.is_a?(Symbol) || parent.is_a?(String) + string << "#{parent}_" + else + string << ActionController::RecordIdentifier.plural_class_name(parent).singularize + string << "_" + end + end + end + + if record.is_a?(Symbol) || record.is_a?(String) + route << "#{record}_" + else + route << ActionController::RecordIdentifier.plural_class_name(record) + route = route.singularize if inflection == :singular + route << "_" + route << "index_" if ActionController::RecordIdentifier.uncountable?(record) && inflection == :plural + end + + action_prefix(options) + route + routing_type(options).to_s + end + + def extract_record(record_or_hash_or_array) + case record_or_hash_or_array + when Array; record_or_hash_or_array.last + when Hash; record_or_hash_or_array[:id] + else record_or_hash_or_array + end + end + end + end +end + diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 980abd44df..662eb05c26 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -82,6 +82,7 @@ module ActionDispatch # module UrlFor extend ActiveSupport::Concern + include PolymorphicRoutes included do # TODO: with_routing extends @controller with url_helpers, trickling down to including this module which overrides its default_url_options diff --git a/actionpack/lib/action_view/helpers/record_identification_helper.rb b/actionpack/lib/action_view/helpers/record_identification_helper.rb index 372f1cb8aa..eea5de9bc6 100644 --- a/actionpack/lib/action_view/helpers/record_identification_helper.rb +++ b/actionpack/lib/action_view/helpers/record_identification_helper.rb @@ -20,4 +20,4 @@ module ActionView end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 56aebca957..137281e5e9 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -37,7 +37,7 @@ module ActionView include ActionController::TemplateAssertions include ActionView::Context - include ActionController::PolymorphicRoutes + include ActionDispatch::Routing::PolymorphicRoutes include ActionController::RecordIdentifier include AbstractController::Helpers |