From dc663dd52c99ab6e6c633b54d1a0e836f379bf9f Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 21 Jun 2012 18:39:35 +0200 Subject: Don't require action_dispatch in ActionView::UrlHelpers ActionDispatch::Routing::UrlFor was always required in UrlHelpers. This was changed by splitting previous implementation of UrlHelper into 2 modules: ActionView::Helpers::UrlHelper and ActionView::Routing::UrlHelper. The former one keeps only basic implementation of url_for. The latter adds features that allow to use routes and is only required when url_helpers or mounted_helpers are required. --- actionpack/lib/action_controller.rb | 4 + actionpack/lib/action_dispatch/routing/url_for.rb | 2 + actionpack/lib/action_view.rb | 1 + actionpack/lib/action_view/helpers/url_helper.rb | 114 +++------------------- actionpack/lib/action_view/routing_url_for.rb | 107 ++++++++++++++++++++ actionpack/lib/action_view/test_case.rb | 1 + actionpack/test/template/erb/helper.rb | 3 +- actionpack/test/template/url_helper_test.rb | 2 +- 8 files changed, 134 insertions(+), 100 deletions(-) create mode 100644 actionpack/lib/action_view/routing_url_for.rb diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 969481928d..0b96c96a2c 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -61,6 +61,10 @@ end require 'action_view' require 'action_view/vendor/html-scanner' +ActiveSupport.on_load(:action_view) do + ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor) +end + # Common Active Support usage in Action Controller require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/load_error' diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index f4c708ea33..5177944575 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -95,6 +95,8 @@ module ActionDispatch self.default_url_options = {} end + + include *_url_for_modules if respond_to?(:_url_for_modules) end def initialize(*) diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 72aba968d1..1cf6937578 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -37,6 +37,7 @@ module ActionView autoload :LookupContext autoload :PathSet autoload :RecordIdentifier + autoload :RoutingUrlFor autoload :Template autoload_under "renderer" do diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index fe3240fdc1..3f65791aa0 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -2,7 +2,6 @@ require 'action_view/helpers/javascript_helper' require 'active_support/core_ext/array/access' require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/string/output_safety' -require 'action_dispatch' module ActionView # = Action View URL Helpers @@ -20,115 +19,34 @@ module ActionView extend ActiveSupport::Concern - include ActionDispatch::Routing::UrlFor include TagHelper - # We need to override url_options, _routes_context - # and optimize_routes_generation? to consider the controller. - - def url_options #:nodoc: - return super unless controller.respond_to?(:url_options) - controller.url_options - end - - def _routes_context #:nodoc: - controller - end - protected :_routes_context - - def optimize_routes_generation? #:nodoc: - controller.respond_to?(:optimize_routes_generation?) ? - controller.optimize_routes_generation? : super + module ClassMethods + def _url_for_modules + ActionView::RoutingUrlFor + end end - protected :optimize_routes_generation? - # Returns the URL for the set of +options+ provided. This takes the - # same options as +url_for+ in Action Controller (see the - # documentation for ActionController::Base#url_for). Note that by default - # :only_path is true so you'll get the relative "/controller/action" - # instead of the fully qualified URL like "http://example.com/controller/action". - # - # ==== Options - # * :anchor - Specifies the anchor name to be appended to the path. - # * :only_path - If true, returns the relative URL (omitting the protocol, host name, and port) (true by default unless :host is specified). - # * :trailing_slash - If true, adds a trailing slash, as in "/archive/2005/". Note that this - # is currently not recommended since it breaks caching. - # * :host - Overrides the default (current) host if provided. - # * :protocol - Overrides the default (current) protocol if provided. - # * :user - Inline HTTP authentication (only plucked out if :password is also present). - # * :password - Inline HTTP authentication (only plucked out if :user is also present). - # - # ==== Relying on named routes - # - # Passing a record (like an Active Record) instead of a hash as the options parameter will - # trigger the named route for that record. The lookup will happen on the name of the class. So passing a - # Workshop object will attempt to use the +workshop_path+ route. If you have a nested route, such as - # +admin_workshop_path+ you'll have to call that explicitly (it's impossible for +url_for+ to guess that route). - # - # ==== Implicit Controller Namespacing - # - # Controllers passed in using the +:controller+ option will retain their namespace unless it is an absolute one. - # - # ==== Examples - # <%= url_for(:action => 'index') %> - # # => /blog/ - # - # <%= url_for(:action => 'find', :controller => 'books') %> - # # => /books/find - # - # <%= url_for(:action => 'login', :controller => 'members', :only_path => false, :protocol => 'https') %> - # # => https://www.example.com/members/login/ - # - # <%= url_for(:action => 'play', :anchor => 'player') %> - # # => /messages/play/#player - # - # <%= url_for(:action => 'jump', :anchor => 'tax&ship') %> - # # => /testing/jump/#tax&ship - # - # <%= url_for(Workshop.new) %> - # # relies on Workshop answering a persisted? call (and in this case returning false) - # # => /workshops - # - # <%= url_for(@workshop) %> - # # calls @workshop.to_param which by default returns the id - # # => /workshops/5 - # - # # to_param can be re-defined in a model to provide different URL names: - # # => /workshops/1-workshop-name - # - # <%= url_for("http://www.example.com") %> - # # => http://www.example.com - # - # <%= url_for(:back) %> - # # if request.env["HTTP_REFERER"] is set to "http://www.example.com" - # # => http://www.example.com - # - # <%= url_for(:back) %> - # # if request.env["HTTP_REFERER"] is not set or is blank - # # => javascript:history.back() - # - # <%= url_for(:action => 'index', :controller => 'users') %> - # # Assuming an "admin" namespace - # # => /admin/users - # - # <%= url_for(:action => 'index', :controller => '/users') %> - # # Specify absolute path with beginning slash - # # => /users - def url_for(options = nil) + # Basic implementation of url_for to allow use helpers without routes existence + def url_for(options = nil) # :nodoc: case options when String options - when nil, Hash - options ||= {} - options = { :only_path => options[:host].nil? }.merge!(options.symbolize_keys) - super when :back - controller.request.env["HTTP_REFERER"] || 'javascript:history.back()' + _back_url else - polymorphic_path(options) + raise ArgumentError, "arguments passed to url_for can't be handled. Please require " + + "routes or provide your own implementation" end end + def _back_url # :nodoc: + referrer = controller.respond_to?(:request) && controller.request.env["HTTP_REFERER"] + referrer || 'javascript:history.back()' + end + protected :_back_url + + # Creates a link tag of the given +name+ using a URL created by the set of +options+. # See the valid options in the documentation for +url_for+. It's also possible to # pass a String instead of an options hash, which generates a link tag that uses the diff --git a/actionpack/lib/action_view/routing_url_for.rb b/actionpack/lib/action_view/routing_url_for.rb new file mode 100644 index 0000000000..13fb6406e1 --- /dev/null +++ b/actionpack/lib/action_view/routing_url_for.rb @@ -0,0 +1,107 @@ +module ActionView + module RoutingUrlFor + + # Returns the URL for the set of +options+ provided. This takes the + # same options as +url_for+ in Action Controller (see the + # documentation for ActionController::Base#url_for). Note that by default + # :only_path is true so you'll get the relative "/controller/action" + # instead of the fully qualified URL like "http://example.com/controller/action". + # + # ==== Options + # * :anchor - Specifies the anchor name to be appended to the path. + # * :only_path - If true, returns the relative URL (omitting the protocol, host name, and port) (true by default unless :host is specified). + # * :trailing_slash - If true, adds a trailing slash, as in "/archive/2005/". Note that this + # is currently not recommended since it breaks caching. + # * :host - Overrides the default (current) host if provided. + # * :protocol - Overrides the default (current) protocol if provided. + # * :user - Inline HTTP authentication (only plucked out if :password is also present). + # * :password - Inline HTTP authentication (only plucked out if :user is also present). + # + # ==== Relying on named routes + # + # Passing a record (like an Active Record) instead of a hash as the options parameter will + # trigger the named route for that record. The lookup will happen on the name of the class. So passing a + # Workshop object will attempt to use the +workshop_path+ route. If you have a nested route, such as + # +admin_workshop_path+ you'll have to call that explicitly (it's impossible for +url_for+ to guess that route). + # + # ==== Implicit Controller Namespacing + # + # Controllers passed in using the +:controller+ option will retain their namespace unless it is an absolute one. + # + # ==== Examples + # <%= url_for(:action => 'index') %> + # # => /blog/ + # + # <%= url_for(:action => 'find', :controller => 'books') %> + # # => /books/find + # + # <%= url_for(:action => 'login', :controller => 'members', :only_path => false, :protocol => 'https') %> + # # => https://www.example.com/members/login/ + # + # <%= url_for(:action => 'play', :anchor => 'player') %> + # # => /messages/play/#player + # + # <%= url_for(:action => 'jump', :anchor => 'tax&ship') %> + # # => /testing/jump/#tax&ship + # + # <%= url_for(Workshop.new) %> + # # relies on Workshop answering a persisted? call (and in this case returning false) + # # => /workshops + # + # <%= url_for(@workshop) %> + # # calls @workshop.to_param which by default returns the id + # # => /workshops/5 + # + # # to_param can be re-defined in a model to provide different URL names: + # # => /workshops/1-workshop-name + # + # <%= url_for("http://www.example.com") %> + # # => http://www.example.com + # + # <%= url_for(:back) %> + # # if request.env["HTTP_REFERER"] is set to "http://www.example.com" + # # => http://www.example.com + # + # <%= url_for(:back) %> + # # if request.env["HTTP_REFERER"] is not set or is blank + # # => javascript:history.back() + # + # <%= url_for(:action => 'index', :controller => 'users') %> + # # Assuming an "admin" namespace + # # => /admin/users + # + # <%= url_for(:action => 'index', :controller => '/users') %> + # # Specify absolute path with beginning slash + # # => /users + def url_for(options = nil) + case options + when String + options + when nil, Hash + options ||= {} + options = { :only_path => options[:host].nil? }.merge!(options.symbolize_keys) + super + when :back + _back_url + else + polymorphic_path(options) + end + end + + def url_options #:nodoc: + return super unless controller.respond_to?(:url_options) + controller.url_options + end + + def _routes_context #:nodoc: + controller + end + protected :_routes_context + + def optimize_routes_generation? #:nodoc: + controller.respond_to?(:optimize_routes_generation?) ? + controller.optimize_routes_generation? : super + end + protected :optimize_routes_generation? + end +end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 17c70b7e95..434fc8cc14 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -42,6 +42,7 @@ module ActionView include AbstractController::Helpers include ActionView::Helpers include ActionView::RecordIdentifier + include ActionView::RoutingUrlFor delegate :lookup_context, :to => :controller attr_accessor :controller, :output_buffer, :rendered diff --git a/actionpack/test/template/erb/helper.rb b/actionpack/test/template/erb/helper.rb index 799f9e4036..a1973068d5 100644 --- a/actionpack/test/template/erb/helper.rb +++ b/actionpack/test/template/erb/helper.rb @@ -1,5 +1,6 @@ module ERBTest class ViewContext + include ActionView::Helpers::UrlHelper include SharedTestRoutes.url_helpers include ActionView::Helpers::TagHelper include ActionView::Helpers::JavaScriptHelper @@ -20,4 +21,4 @@ module ERBTest "<%= #{str} do %>#{rest}<% end %>" end end -end \ No newline at end of file +end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index f9f8c36fff..9c4271f19b 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -20,9 +20,9 @@ class UrlHelperTest < ActiveSupport::TestCase get "/article/:id" => "foo#article", :as => :article end + include ActionView::Helpers::UrlHelper include routes.url_helpers - include ActionView::Helpers::UrlHelper include ActionView::Helpers::JavaScriptHelper include ActionDispatch::Assertions::DomAssertions include ActionView::Context -- cgit v1.2.3