From 2c08ee97c78b7eb0883f1b0347c69a088c109388 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 26 Nov 2010 00:21:51 +0100 Subject: move the setting up of the mime collector into the collector on init --- actionpack/lib/action_controller/metal/mime_responds.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 6fe1f4ece5..2e58155b7c 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -258,9 +258,8 @@ module ActionController #:nodoc: # nil if :not_acceptable was sent to the client. # def retrieve_response_from_mimes(mimes=nil, &block) - collector = Collector.new { default_render } mimes ||= collect_mimes_from_class_level - mimes.each { |mime| collector.send(mime) } + collector = Collector.new(mimes) { default_render } block.call(collector) if block_given? if format = request.negotiate_mime(collector.order) @@ -277,8 +276,9 @@ module ActionController #:nodoc: include AbstractController::Collector attr_accessor :order - def initialize(&block) + def initialize(mimes, &block) @order, @responses, @default_response = [], {}, block + mimes.each { |mime| self.send(mime) } end def any(*args, &block) -- cgit v1.2.3 From 927c582acfb9253be493e7ec584c0503555e00fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 27 Nov 2010 08:12:49 -0800 Subject: Update CHANGELOG. --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 74d017cc3d..2ab2ca1542 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.1.0 (unreleased)* +* url_for and named url helpers now accept :subdomain and :domain as options [Josh Kalderimis] + * Added config.action_controller.include_all_helpers. By default 'helper :all' is done in ActionController::Base, which includes all the helpers by default. Setting include_all_helpers to false will result in including only application_helper and helper corresponding to controller (like foo_helper for foo_controller). [Piotr Sarnacki] * Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options: -- cgit v1.2.3 From 1662aa1a15ad3f2218f85e4bd58aea56708a87a1 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Thu, 11 Nov 2010 05:27:40 +0900 Subject: Added a space before "do" keyword --- actionpack/lib/action_view/helpers/form_tag_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 92645f5cf9..50f065f03d 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -39,7 +39,7 @@ module ActionView # form_tag('/upload', :multipart => true) # # =>
# - # <%= form_tag('/posts')do -%> + # <%= form_tag('/posts') do -%> #
<%= submit_tag 'Save' %>
# <% end -%> # # =>
-- cgit v1.2.3 From 9bd291407c70daac1b2777f552f599a6fff9f387 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Sat, 27 Nov 2010 22:16:51 -0500 Subject: make it clear that recompilation happens only in development mode --- actionpack/lib/action_view/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 1beae37af3..15944138f7 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -76,8 +76,8 @@ module ActionView #:nodoc: # # === Template caching # - # By default, Rails will compile each template to a method in order to render it. When you alter a template, Rails will - # check the file's modification time and recompile it. + # By default, Rails will compile each template to a method in order to render it. When you alter a template, + # Rails will check the file's modification time and recompile it in development mode. # # == Builder # -- cgit v1.2.3 From a4c360e8c7b7c2635de3c1172dafff7b7975ecc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 28 Nov 2010 11:48:39 +0100 Subject: trailing star mimes should respect the order in which mime types are defined. --- actionpack/lib/action_dispatch/http/mime_type.rb | 18 +++++++++++------- actionpack/test/dispatch/mime_type_test.rb | 19 ++++++------------- 2 files changed, 17 insertions(+), 20 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 08eab5634a..3e3478a44e 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -115,15 +115,20 @@ module Mime end else # keep track of creation order to keep the subsequent sort stable - list = [] - accept_header.split(/,/).each_with_index do |header, index| + list, index = [], 0 + accept_header.split(/,/).each do |header| params, q = header.split(/;\s*q=/) - if params + if params.present? params.strip! + if params =~ TRAILING_STAR_REGEXP - parse_data_with_trailing_star($1).each { |m| list << AcceptItem.new(index, m.to_s, q) } + parse_data_with_trailing_star($1).each do |m| + list << AcceptItem.new(index, m.to_s, q) + index += 1 + end else - list << AcceptItem.new(index, params, q) unless params.empty? + list << AcceptItem.new(index, params, q) + index += 1 end end end @@ -178,8 +183,7 @@ module Mime # input: 'application' # returend value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM def parse_data_with_trailing_star(input) - keys = Mime::LOOKUP.keys.select{|k| k.include?(input)} - Mime::LOOKUP.values_at(*keys).uniq + Mime::SET.select { |m| m =~ input } end # This method is opposite of register method. diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 9424d88498..e80d339472 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -31,30 +31,23 @@ class MimeTypeTest < ActiveSupport::TestCase test "parse text with trailing star at the beginning" do accept = "text/*, text/html, application/json, multipart/form-data" - expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::TEXT, Mime::YAML, Mime::JS, Mime::MULTIPART_FORM] + expect = [Mime::HTML, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::XML, Mime::YAML, Mime::JSON, Mime::MULTIPART_FORM] parsed = Mime::Type.parse(accept) - assert_equal expect.size, parsed.size - Range.new(0,expect.size-1).to_a.each do |index| - assert_equal expect[index], parsed[index], "Failed for index number #{index}" - end + assert_equal expect, parsed end test "parse text with trailing star in the end" do accept = "text/html, application/json, multipart/form-data, text/*" - expect = [Mime::HTML, Mime::JSON, Mime::MULTIPART_FORM, Mime::XML, Mime::ICS, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] + expect = [Mime::HTML, Mime::JSON, Mime::MULTIPART_FORM, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::XML, Mime::YAML] parsed = Mime::Type.parse(accept) - assert_equal 10, parsed.size - Range.new(0,expect.size-1).to_a.each do |index| - assert_equal expect[index], parsed[index], "Failed for index number #{index}" - end + assert_equal expect, parsed end test "parse text with trailing star" do accept = "text/*" - expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT].sort_by(&:to_s) + expect = [Mime::HTML, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::XML, Mime::YAML, Mime::JSON] parsed = Mime::Type.parse(accept) - assert_equal 9, parsed.size - assert_equal expect, parsed.sort_by(&:to_s) + assert_equal expect, parsed end test "parse application with trailing star" do -- cgit v1.2.3 From 31906eecdf7bffc2203379c5d40f1bb77fb35858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 28 Nov 2010 12:48:50 +0100 Subject: Fix tests on 1.9.2. --- actionpack/lib/action_dispatch/http/mime_type.rb | 15 +++++++++------ actionpack/test/controller/mime_responds_test.rb | 16 +++++++++------- actionpack/test/dispatch/mime_type_test.rb | 9 ++++----- actionpack/test/lib/controller/fake_models.rb | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 3e3478a44e..c1503c7eeb 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -190,12 +190,15 @@ module Mime # # Usage: # - # Mime::Type.unregister("text/x-mobile", :mobile) - def unregister(string, symbol) - EXTENSION_LOOKUP.delete(symbol.to_s) - LOOKUP.delete(string) - symbol = symbol.to_s.upcase.intern - Mime.module_eval { remove_const(symbol) if const_defined?(symbol) } + # Mime::Type.unregister(:mobile) + def unregister(symbol) + symbol = symbol.to_s.upcase + mime = Mime.const_get(symbol) + Mime.instance_eval { remove_const(symbol) } + + SET.delete_if { |v| v.eql?(mime) } + LOOKUP.delete_if { |k,v| v.eql?(mime) } + EXTENSION_LOOKUP.delete_if { |k,v| v.eql?(mime) } end end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 82969b2979..98c9d43b93 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -201,8 +201,8 @@ class RespondToControllerTest < ActionController::TestCase def teardown super - Mime::Type.unregister('text/x-mobile', :iphone) - Mime::Type.unregister('text/iphone', :mobile) + Mime::Type.unregister(:iphone) + Mime::Type.unregister(:mobile) end def test_html @@ -622,12 +622,14 @@ class RespondWithControllerTest < ActionController::TestCase def setup super @request.host = "www.example.com" + Mime::Type.register_alias('text/html', :iphone) + Mime::Type.register('text/x-mobile', :mobile) end def teardown super - Mime::Type.unregister('text/x-mobile', :iphone) - Mime::Type.unregister('text/iphone', :mobile) + Mime::Type.unregister(:iphone) + Mime::Type.unregister(:mobile) end def test_using_resource @@ -929,7 +931,8 @@ class RespondWithControllerTest < ActionController::TestCase @controller = RenderJsonRespondWithController.new @request.accept = "application/json" get :index, :format => :json - assert_equal %Q{{"message":"boom","error":"RenderJsonTestException"}}, @response.body + assert_match(/"message":"boom"/, @response.body) + assert_match(/"error":"RenderJsonTestException"/, @response.body) end def test_no_double_render_is_raised @@ -1020,8 +1023,7 @@ class MimeControllerLayoutsTest < ActionController::TestCase def teardown super - Mime::Type.unregister('text/x-mobile', :iphone) - Mime::Type.unregister('text/iphone', :mobile) + Mime::Type.unregister(:iphone) end def test_missing_layout_renders_properly diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index e80d339472..9782f328fc 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -19,7 +19,7 @@ class MimeTypeTest < ActiveSupport::TestCase assert_equal Mime::MOBILE, Mime::LOOKUP['text/x-mobile'] assert_equal Mime::MOBILE, Mime::EXTENSION_LOOKUP['mobile'] - Mime::Type.unregister("text/x-mobile", :mobile) + Mime::Type.unregister(:mobile) assert !defined?(Mime::MOBILE), "Mime::MOBILE should not be defined" assert !Mime::LOOKUP.has_key?('text/x-mobile'), "Mime::LOOKUP should not have key ['text/x-mobile]" assert !Mime::EXTENSION_LOOKUP.has_key?('mobile'), "Mime::EXTENSION_LOOKUP should not have key ['mobile]" @@ -52,10 +52,9 @@ class MimeTypeTest < ActiveSupport::TestCase test "parse application with trailing star" do accept = "application/*" - expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::PDF, Mime::URL_ENCODED_FORM].sort_by(&:to_s) + expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::RSS, Mime::ATOM, Mime::YAML, Mime::URL_ENCODED_FORM, Mime::JSON, Mime::PDF] parsed = Mime::Type.parse(accept) - assert_equal 9, parsed.size - assert_equal expect, parsed.sort_by(&:to_s) + assert_equal expect, parsed end test "parse without q" do @@ -92,7 +91,7 @@ class MimeTypeTest < ActiveSupport::TestCase assert_equal Mime::GIF, Mime::SET.last end ensure - Mime::Type.unregister('image/gif', :gif) + Mime::Type.unregister(:gif) end end diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index bd18cdc1b8..67baf369e2 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -197,6 +197,6 @@ end class RenderJsonTestException < Exception def to_json(options = nil) - return { :error => self.class.name, :message => self.to_str }.to_json + return { :error => self.class.name, :message => self.to_s }.to_json end end -- cgit v1.2.3 From aa9a3227a0151af87e1eb5a6c4b7b0b095fc33c9 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 29 Nov 2010 21:38:37 -0500 Subject: Rewording existing comment --- actionpack/lib/abstract_controller/layouts.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index b68c7d9216..606f7eedec 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -235,13 +235,10 @@ module AbstractController controller_path end - # Takes the specified layout and creates a _layout method to be called - # by _default_layout + # Creates a _layout method to be called by _default_layout . # - # If there is no explicit layout specified: - # If a layout is found in the view paths with the controller's - # name, return that string. Otherwise, use the superclass' - # layout (which might also be implied) + # If a layout is not explicitly mentioned then look for a layout with the controller's name. + # if nothing is found then try same procedure to find super class's layout. def _write_layout_method remove_possible_method(:_layout) -- cgit v1.2.3 From 3c7a33c0510e30a3017b007d8ed8afcae02ef4a6 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Tue, 30 Nov 2010 10:00:47 -0500 Subject: Rewording existing comment --- actionpack/lib/abstract_controller/base.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index f83eaded88..c384fd0978 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -31,10 +31,9 @@ module AbstractController # A list of all internal methods for a controller. This finds the first # abstract superclass of a controller, and gets a list of all public # instance methods on that abstract class. Public instance methods of - # a controller would normally be considered action methods, so we - # are removing those methods on classes declared as abstract - # (ActionController::Metal and ActionController::Base are defined - # as abstract) + # a controller would normally be considered action methods, so methods + # declared on abstract classes are being removed. + # (ActionController::Metal and ActionController::Base are defined as abstract) def internal_methods controller = self controller = controller.superclass until controller.abstract? -- cgit v1.2.3 From 0bda6f1ec664fcfd1b312492a6419e3d76d5baa7 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Tue, 30 Nov 2010 16:36:01 +0100 Subject: The redirect routing method now allows for a hash of options which only changes the relevant parts of the url, or an object which responds to call can be supplied so common redirect rules can be easily reused. This commit includes a change where url generation from parts has been moved to AD::Http::URL as a class method. --- actionpack/lib/action_dispatch/http/url.rb | 52 ++ actionpack/lib/action_dispatch/routing/mapper.rb | 39 +- .../lib/action_dispatch/routing/redirection.rb | 81 +++ .../lib/action_dispatch/routing/route_set.rb | 62 +-- actionpack/test/controller/routing_test.rb | 581 +++++++++++---------- actionpack/test/dispatch/request_test.rb | 25 + actionpack/test/dispatch/routing_test.rb | 48 ++ 7 files changed, 525 insertions(+), 363 deletions(-) create mode 100644 actionpack/lib/action_dispatch/routing/redirection.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index 1e7054f381..51d4766282 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -24,6 +24,58 @@ module ActionDispatch !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host)) end + def self.url_for(options = {}) + unless options[:host].present? || options[:only_path].present? + raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' + end + + rewritten_url = "" + + unless options[:only_path] + rewritten_url << (options[:protocol] || "http") + rewritten_url << "://" unless rewritten_url.match("://") + rewritten_url << rewrite_authentication(options) + rewritten_url << host_or_subdomain_and_domain(options) + rewritten_url << ":#{options.delete(:port)}" if options[:port] + end + + path = options.delete(:path) || '' + + params = options[:params] || {} + params.reject! {|k,v| !v } + + rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) + rewritten_url << "?#{params.to_query}" unless params.empty? + rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor] + rewritten_url + end + + class << self + private + + def rewrite_authentication(options) + if options[:user] && options[:password] + "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@" + else + "" + end + end + + def host_or_subdomain_and_domain(options) + return options[:host] unless options[:subdomain] || options[:domain] + + tld_length = options[:tld_length] || @@tld_length + + host = "" + host << (options[:subdomain] || extract_subdomain(options[:host], tld_length)) + host << "." + host << (options[:domain] || extract_domain(options[:host], tld_length)) + host + end + + end + + # Returns the complete URL used for this request. def url diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 880862c909..05b7147c70 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -2,6 +2,7 @@ require 'erb' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/object/blank' require 'active_support/inflector' +require 'action_dispatch/routing/redirection' module ActionDispatch module Routing @@ -383,39 +384,6 @@ module ActionDispatch map_method(:delete, *args, &block) end - # Redirect any path to another path: - # - # match "/stories" => redirect("/posts") - def redirect(*args) - options = args.last.is_a?(Hash) ? args.pop : {} - - path = args.shift || Proc.new - path_proc = path.is_a?(Proc) ? path : proc { |params| (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % params) } - status = options[:status] || 301 - - lambda do |env| - req = Request.new(env) - - params = [req.symbolized_path_parameters] - params << req if path_proc.arity > 1 - - uri = URI.parse(path_proc.call(*params)) - uri.scheme ||= req.scheme - uri.host ||= req.host - uri.port ||= req.port unless req.standard_port? - - body = %(You are being redirected.) - - headers = { - 'Location' => uri.to_s, - 'Content-Type' => 'text/html', - 'Content-Length' => body.length.to_s - } - - [ status, headers, [body] ] - end - end - private def map_method(method, *args, &block) options = args.extract_options! @@ -638,7 +606,7 @@ module ActionDispatch :shallow_path => path, :shallow_prefix => path }.merge!(options) scope(options) { yield } end - + # === Parameter Restriction # Allows you to constrain the nested routes based on a set of rules. # For instance, in order to change the routes to allow for a dot character in the +id+ parameter: @@ -649,7 +617,7 @@ module ActionDispatch # # Now routes such as +/posts/1+ will no longer be valid, but +/posts/1.1+ will be. # The +id+ parameter must match the constraint passed in for this example. - # + # # You may use this to also resrict other parameters: # # resources :posts do @@ -1340,6 +1308,7 @@ module ActionDispatch include Base include HttpHelpers + include Redirection include Scoping include Resources include Shorthand diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb new file mode 100644 index 0000000000..d9c9a400a7 --- /dev/null +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -0,0 +1,81 @@ +require 'action_dispatch/http/request' + +module ActionDispatch + module Routing + module Redirection + + # Redirect any path to another path: + # + # match "/stories" => redirect("/posts") + def redirect(*args, &block) + options = args.last.is_a?(Hash) ? args.pop : {} + status = options.delete(:status) || 301 + + path = args.shift + + path_proc = if path.is_a?(String) + proc { |params| (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % params) } + elsif options.any? + options_proc(options) + elsif path.respond_to?(:call) + proc { |params, request| path.call(params, request) } + elsif block + block + else + raise ArgumentError, "redirection argument not supported" + end + + redirection_proc(status, path_proc) + end + + private + + def options_proc(options) + proc do |params, request| + path = if options[:path].nil? + request.path + elsif params.empty? || !options[:path].match(/%\{\w*\}/) + options.delete(:path) + else + (options.delete(:path) % params) + end + + default_options = { + :protocol => request.protocol, + :host => request.host, + :port => request.optional_port, + :path => path, + :params => request.query_parameters + } + + ActionDispatch::Http::URL.url_for(options.reverse_merge(default_options)) + end + end + + def redirection_proc(status, path_proc) + lambda do |env| + req = Request.new(env) + + params = [req.symbolized_path_parameters] + params << req if path_proc.arity > 1 + + uri = URI.parse(path_proc.call(*params)) + uri.scheme ||= req.scheme + uri.host ||= req.host + uri.port ||= req.port unless req.standard_port? + + body = %(You are being redirected.) + + headers = { + 'Location' => uri.to_s, + 'Content-Type' => 'text/html', + 'Content-Length' => body.length.to_s + } + + [ status, headers, [body] ] + end + end + + end + end +end \ No newline at end of file diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index ebced9cabe..03bfe178e5 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -442,12 +442,9 @@ module ActionDispatch raise_routing_error unless path - params.reject! {|k,v| !v } - return [path, params.keys] if @extras - path << "?#{params.to_query}" unless params.empty? - path + [path, params] rescue Rack::Mount::RoutingError raise_routing_error end @@ -486,7 +483,7 @@ module ActionDispatch end RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length, - :trailing_slash, :script_name, :anchor, :params, :only_path ] + :trailing_slash, :anchor, :params, :only_path, :script_name] def _generate_prefix(options = {}) nil @@ -498,29 +495,24 @@ module ActionDispatch handle_positional_args(options) - rewritten_url = "" - - path_segments = options.delete(:_path_segments) - unless options[:only_path] - rewritten_url << (options[:protocol] || "http") - rewritten_url << "://" unless rewritten_url.match("://") - rewritten_url << rewrite_authentication(options) - rewritten_url << host_from_options(options) - rewritten_url << ":#{options.delete(:port)}" if options[:port] - end + user, password = extract_authentication(options) + path_segments = options.delete(:_path_segments) + script_name = options.delete(:script_name) - script_name = options.delete(:script_name) path = (script_name.blank? ? _generate_prefix(options) : script_name.chomp('/')).to_s path_options = options.except(*RESERVED_OPTIONS) path_options = yield(path_options) if block_given? - path << generate(path_options, path_segments || {}) - # ROUTES TODO: This can be called directly, so script_name should probably be set in the routes - rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) - rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor] + path_addition, params = generate(path_options, path_segments || {}) + path << path_addition - rewritten_url + ActionDispatch::Http::URL.url_for(options.merge({ + :path => path, + :params => params, + :user => user, + :password => password + })) end def call(env) @@ -561,23 +553,12 @@ module ActionDispatch private - def host_from_options(options) - computed_host = subdomain_and_domain(options) || options[:host] - unless computed_host - raise ArgumentError, "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" + def extract_authentication(options) + if options[:user] && options[:password] + [options.delete(:user), options.delete(:password)] + else + nil end - computed_host - end - - def subdomain_and_domain(options) - return nil unless options[:subdomain] || options[:domain] - tld_length = options[:tld_length] || ActionDispatch::Http::URL.tld_length - - host = "" - host << (options[:subdomain] || ActionDispatch::Http::URL.extract_subdomain(options[:host], tld_length)) - host << "." - host << (options[:domain] || ActionDispatch::Http::URL.extract_domain(options[:host], tld_length)) - host end def handle_positional_args(options) @@ -590,13 +571,6 @@ module ActionDispatch options.merge!(Hash[args.zip(keys).map { |v, k| [k, v] }]) end - def rewrite_authentication(options) - if options[:user] && options[:password] - "#{Rack::Utils.escape(options.delete(:user))}:#{Rack::Utils.escape(options.delete(:password))}@" - else - "" - end - end end end end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index cd067b7d18..89f0d03c56 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -12,8 +12,16 @@ end ROUTING = ActionDispatch::Routing +module RoutingTestHelpers + def url_for(set, options, recall = nil) + set.send(:url_for, options.merge(:only_path => true, :_path_segments => recall)) + end +end + # See RFC 3986, section 3.3 for allowed path characters. class UriReservedCharactersRoutingTest < Test::Unit::TestCase + include RoutingTestHelpers + def setup @set = ActionDispatch::Routing::RouteSet.new @set.draw do @@ -28,12 +36,13 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase end def test_route_generation_escapes_unsafe_path_characters - @set.generate(:controller => "content", :action => "act#{@segment}ion", :variable => "variable", :additional => "foo") assert_equal "/content/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2", - @set.generate(:controller => "content", - :action => "act#{@segment}ion", - :variable => "var#{@segment}iable", - :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"]) + url_for(@set, { + :controller => "content", + :action => "act#{@segment}ion", + :variable => "var#{@segment}iable", + :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"] + }) end def test_route_recognition_unescapes_path_components @@ -45,10 +54,13 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase end def test_route_generation_allows_passing_non_string_values_to_generated_helper - assert_equal "/content/action/variable/1/2", @set.generate(:controller => "content", - :action => "action", - :variable => "variable", - :additional => [1, 2]) + assert_equal "/content/action/variable/1/2", + url_for(@set, { + :controller => "content", + :action => "action", + :variable => "variable", + :additional => [1, 2] + }) end end @@ -68,6 +80,8 @@ class MockController end class LegacyRouteSetTests < Test::Unit::TestCase + include RoutingTestHelpers + attr_reader :rs def setup @@ -81,18 +95,18 @@ class LegacyRouteSetTests < Test::Unit::TestCase def test_default_setup @rs.draw { match '/:controller(/:action(/:id))' } assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content")) - assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list")) + assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list")) assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10")) assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10")) - assert_equal '/admin/user/show/10', rs.generate(:controller => 'admin/user', :action => 'show', :id => 10) + assert_equal '/admin/user/show/10', url_for(rs, { :controller => 'admin/user', :action => 'show', :id => 10 }) - assert_equal '/admin/user/show', rs.generate({:action => 'show'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) - assert_equal '/admin/user/list/10', rs.generate({}, {:controller => 'admin/user', :action => 'list', :id => '10'}) + assert_equal '/admin/user/show', url_for(rs, { :action => 'show' }, { :controller => 'admin/user', :action => 'list', :id => '10' }) + assert_equal '/admin/user/list/10', url_for(rs, {}, { :controller => 'admin/user', :action => 'list', :id => '10' }) - assert_equal '/admin/stuff', rs.generate({:controller => 'stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) - assert_equal '/stuff', rs.generate({:controller => '/stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'}) + assert_equal '/admin/stuff', url_for(rs, { :controller => 'stuff' }, { :controller => 'admin/user', :action => 'list', :id => '10' }) + assert_equal '/stuff', url_for(rs, { :controller => '/stuff' }, { :controller => 'admin/user', :action => 'list', :id => '10' }) end def test_ignores_leading_slash @@ -143,11 +157,14 @@ class LegacyRouteSetTests < Test::Unit::TestCase match ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/ match '/:controller(/:action(/:id))' end + assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"}, rs.recognize_path("/admin/user/foo")) - assert_equal({:controller => "content", :action => "foo"}, rs.recognize_path("/content/foo")) - assert_equal '/admin/user/foo', rs.generate(:controller => "admin/user", :admintoken => "foo", :action => "index") - assert_equal '/content/foo', rs.generate(:controller => "content", :action => "foo") + assert_equal({:controller => "content", :action => "foo"}, + rs.recognize_path("/content/foo")) + + assert_equal '/admin/user/foo', url_for(rs, { :controller => "admin/user", :admintoken => "foo", :action => "index" }) + assert_equal '/content/foo', url_for(rs, { :controller => "content", :action => "foo" }) end def test_route_with_regexp_and_captures_for_controller @@ -169,17 +186,16 @@ class LegacyRouteSetTests < Test::Unit::TestCase end # Without a file extension assert_equal '/user/download/file', - rs.generate(:controller => "user", :action => "download", :file => "file") - assert_equal( - {:controller => "user", :action => "download", :file => "file"}, + url_for(rs, { :controller => "user", :action => "download", :file => "file" }) + + assert_equal({:controller => "user", :action => "download", :file => "file"}, rs.recognize_path("/user/download/file")) # Now, let's try a file with an extension, really a dot (.) assert_equal '/user/download/file.jpg', - rs.generate( - :controller => "user", :action => "download", :file => "file.jpg") - assert_equal( - {:controller => "user", :action => "download", :file => "file.jpg"}, + url_for(rs, { :controller => "user", :action => "download", :file => "file.jpg" }) + + assert_equal({:controller => "user", :action => "download", :file => "file.jpg"}, rs.recognize_path("/user/download/file.jpg")) end @@ -187,28 +203,25 @@ class LegacyRouteSetTests < Test::Unit::TestCase rs.draw do root :to => 'content#list', :as => 'home' end - x = setup_for_named_route - assert_equal("http://test.host/", - x.send(:home_url)) + assert_equal("http://test.host/", setup_for_named_route.send(:home_url)) end def test_named_route_with_option rs.draw do match 'page/:title' => 'content#show_page', :as => 'page' end - x = setup_for_named_route + assert_equal("http://test.host/page/new%20stuff", - x.send(:page_url, :title => 'new stuff')) + setup_for_named_route.send(:page_url, :title => 'new stuff')) end def test_named_route_with_default rs.draw do match 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page' end - x = setup_for_named_route - assert_equal("http://test.host/page/AboutRails", - x.send(:page_url, :title => "AboutRails")) + assert_equal("http://test.host/page/AboutRails", + setup_for_named_route.send(:page_url, :title => "AboutRails")) end def test_named_route_with_path_prefix @@ -217,9 +230,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase match 'page' => 'content#show_page', :as => 'page' end end - x = setup_for_named_route + assert_equal("http://test.host/my/page", - x.send(:page_url)) + setup_for_named_route.send(:page_url)) end def test_named_route_with_blank_path_prefix @@ -228,27 +241,33 @@ class LegacyRouteSetTests < Test::Unit::TestCase match 'page' => 'content#show_page', :as => 'page' end end - x = setup_for_named_route + assert_equal("http://test.host/page", - x.send(:page_url)) + setup_for_named_route.send(:page_url)) end def test_named_route_with_nested_controller rs.draw do match 'admin/user' => 'admin/user#index', :as => "users" end - x = setup_for_named_route + assert_equal("http://test.host/admin/user", - x.send(:users_url)) + setup_for_named_route.send(:users_url)) end def test_optimised_named_route_with_host rs.draw do match 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com' end - x = setup_for_named_route - x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => 'pages').once - x.send(:pages_url) + routes = setup_for_named_route + routes.expects(:url_for).with({ + :host => 'foo.com', + :only_path => false, + :controller => 'content', + :action => 'show_page', + :use_route => 'pages' + }).once + routes.send(:pages_url) end def setup_for_named_route @@ -265,9 +284,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase rs.draw do root :to => "hello#index" end - x = setup_for_named_route - assert_equal("http://test.host/", x.send(:root_url)) - assert_equal("/", x.send(:root_path)) + routes = setup_for_named_route + assert_equal("http://test.host/", routes.send(:root_url)) + assert_equal("/", routes.send(:root_path)) end def test_named_route_with_regexps @@ -276,24 +295,19 @@ class LegacyRouteSetTests < Test::Unit::TestCase :year => /\d+/, :month => /\d+/, :day => /\d+/ match ':controller/:action/:id' end - x = setup_for_named_route - # assert_equal( - # {:controller => 'page', :action => 'show', :title => 'hi', :use_route => :article, :only_path => false}, - # x.send(:article_url, :title => 'hi') - # ) - assert_equal( - "http://test.host/page/2005/6/10/hi", - x.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6) - ) + + routes = setup_for_named_route + + assert_equal "http://test.host/page/2005/6/10/hi", + routes.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6) end def test_changing_controller @rs.draw { match ':controller/:action/:id' } - assert_equal '/admin/stuff/show/10', rs.generate( - {:controller => 'stuff', :action => 'show', :id => 10}, - {:controller => 'admin/user', :action => 'index'} - ) + assert_equal '/admin/stuff/show/10', + url_for(rs, {:controller => 'stuff', :action => 'show', :id => 10}, + {:controller => 'admin/user', :action => 'index'}) end def test_paths_escaped @@ -319,8 +333,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase end # No / to %2F in URI, only for query params. - x = setup_for_named_route - assert_equal("/file/hello/world", x.send(:path_path, ['hello', 'world'])) + assert_equal("/file/hello/world", setup_for_named_route.send(:path_path, ['hello', 'world'])) end def test_non_controllers_cannot_be_matched @@ -334,7 +347,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase rs.draw do match 'post/:id' => 'post#show', :constraints => { :id => /\d+/ }, :as => 'post' end - assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") } + assert_raise(ActionController::RoutingError) do + url_for(rs, { :controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post" }) + end end def test_dynamic_path_allowed @@ -342,7 +357,8 @@ class LegacyRouteSetTests < Test::Unit::TestCase match '*path' => 'content#show_file' end - assert_equal '/pages/boo', rs.generate(:controller => 'content', :action => 'show_file', :path => %w(pages boo)) + assert_equal '/pages/boo', + url_for(rs, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) }) end def test_dynamic_recall_paths_allowed @@ -350,7 +366,8 @@ class LegacyRouteSetTests < Test::Unit::TestCase match '*path' => 'content#show_file' end - assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => %w(pages boo)) + assert_equal '/pages/boo', + url_for(rs, {}, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) }) end def test_backwards @@ -359,9 +376,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase match ':controller(/:action(/:id))' end - assert_equal '/page/20', rs.generate({:id => 20}, {:controller => 'pages', :action => 'show'}) - assert_equal '/page/20', rs.generate(:controller => 'pages', :id => 20, :action => 'show') - assert_equal '/pages/boo', rs.generate(:controller => 'pages', :action => 'boo') + assert_equal '/page/20', url_for(rs, { :id => 20 }, { :controller => 'pages', :action => 'show' }) + assert_equal '/page/20', url_for(rs, { :controller => 'pages', :id => 20, :action => 'show' }) + assert_equal '/pages/boo', url_for(rs, { :controller => 'pages', :action => 'boo' }) end def test_route_with_fixnum_default @@ -370,10 +387,10 @@ class LegacyRouteSetTests < Test::Unit::TestCase match ':controller/:action/:id' end - assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page') - assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => 1) - assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => '1') - assert_equal '/page/10', rs.generate(:controller => 'content', :action => 'show_page', :id => 10) + assert_equal '/page', url_for(rs, { :controller => 'content', :action => 'show_page' }) + assert_equal '/page', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 1 }) + assert_equal '/page', url_for(rs, { :controller => 'content', :action => 'show_page', :id => '1' }) + assert_equal '/page/10', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 10 }) assert_equal({:controller => "content", :action => 'show_page', :id => 1 }, rs.recognize_path("/page")) assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1")) @@ -387,20 +404,20 @@ class LegacyRouteSetTests < Test::Unit::TestCase match ':controller/:action/:id' end - assert_equal '/page/foo', rs.generate(:controller => 'content', :action => 'show_page', :id => 'foo') - assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo")) + assert_equal '/page/foo', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 'foo' }) + assert_equal({ :controller => "content", :action => 'show_page', :id => 'foo' }, rs.recognize_path("/page/foo")) token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian token.force_encoding(Encoding::BINARY) if token.respond_to?(:force_encoding) escaped_token = CGI::escape(token) - assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token) - assert_equal({:controller => "content", :action => 'show_page', :id => token}, rs.recognize_path("/page/#{escaped_token}")) + assert_equal '/page/' + escaped_token, url_for(rs, { :controller => 'content', :action => 'show_page', :id => token }) + assert_equal({ :controller => "content", :action => 'show_page', :id => token }, rs.recognize_path("/page/#{escaped_token}")) end def test_action_expiry @rs.draw { match ':controller(/:action(/:id))' } - assert_equal '/content', rs.generate({:controller => 'content'}, {:controller => 'content', :action => 'show'}) + assert_equal '/content', url_for(rs, { :controller => 'content' }, { :controller => 'content', :action => 'show' }) end def test_requirement_should_prevent_optional_id @@ -408,10 +425,10 @@ class LegacyRouteSetTests < Test::Unit::TestCase match 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post' end - assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10) + assert_equal '/post/10', url_for(rs, { :controller => 'post', :action => 'show', :id => 10 }) assert_raise ActionController::RoutingError do - rs.generate(:controller => 'post', :action => 'show') + url_for(rs, { :controller => 'post', :action => 'show' }) end end @@ -424,12 +441,10 @@ class LegacyRouteSetTests < Test::Unit::TestCase match ':controller/:action/:id' end - assert_equal '/test', rs.generate(:controller => 'post', :action => 'show') - assert_equal '/test', rs.generate(:controller => 'post', :action => 'show', :year => nil) + assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show' }) + assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show', :year => nil }) - x = setup_for_named_route - assert_equal("http://test.host/test", - x.send(:blog_url)) + assert_equal("http://test.host/test", setup_for_named_route.send(:blog_url)) end def test_set_to_nil_forgets @@ -439,20 +454,20 @@ class LegacyRouteSetTests < Test::Unit::TestCase end assert_equal '/pages/2005', - rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005) + url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005 }) assert_equal '/pages/2005/6', - rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6) + url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6 }) assert_equal '/pages/2005/6/12', - rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12) + url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12 }) assert_equal '/pages/2005/6/4', - rs.generate({:day => 4}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) + url_for(rs, { :day => 4 }, { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' }) assert_equal '/pages/2005/6', - rs.generate({:day => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) + url_for(rs, { :day => nil }, { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' }) assert_equal '/pages/2005', - rs.generate({:day => nil, :month => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'}) + url_for(rs, { :day => nil, :month => nil }, { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' }) end def test_root_url_generation_with_controller_and_action @@ -460,8 +475,8 @@ class LegacyRouteSetTests < Test::Unit::TestCase root :to => "content#index" end - assert_equal '/', rs.generate(:controller => 'content', :action => 'index') - assert_equal '/', rs.generate(:controller => 'content') + assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' }) + assert_equal '/', url_for(rs, { :controller => 'content' }) end def test_named_root_url_generation_with_controller_and_action @@ -469,12 +484,10 @@ class LegacyRouteSetTests < Test::Unit::TestCase root :to => "content#index", :as => 'home' end - assert_equal '/', rs.generate(:controller => 'content', :action => 'index') - assert_equal '/', rs.generate(:controller => 'content') + assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' }) + assert_equal '/', url_for(rs, { :controller => 'content' }) - x = setup_for_named_route - assert_equal("http://test.host/", - x.send(:home_url)) + assert_equal("http://test.host/", setup_for_named_route.send(:home_url)) end def test_named_route_method @@ -483,8 +496,8 @@ class LegacyRouteSetTests < Test::Unit::TestCase match ':controller(/:action(/:id))' end - assert_equal '/categories', rs.generate(:controller => 'content', :action => 'categories') - assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'}) + assert_equal '/categories', url_for(rs, { :controller => 'content', :action => 'categories' }) + assert_equal '/content/hi', url_for(rs, { :controller => 'content', :action => 'hi' }) end def test_named_routes_array @@ -499,7 +512,12 @@ class LegacyRouteSetTests < Test::Unit::TestCase match ':controller/:action/:id' end - assert_equal '/journal', rs.generate(:controller => 'content', :action => 'list_journal', :date => nil, :user_id => nil) + assert_equal '/journal', url_for(rs, { + :controller => 'content', + :action => 'list_journal', + :date => nil, + :user_id => nil + }) end def setup_request_method_routes_for(method) @@ -564,9 +582,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase match '/posts/new/:action' => 'subpath_books' end - assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit") - assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete") - assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview") + assert_equal "/books/7/edit", url_for(rs, { :controller => "subpath_books", :id => 7, :action => "edit" }) + assert_equal "/items/15/complete", url_for(rs, { :controller => "subpath_books", :id => 15, :action => "complete" }) + assert_equal "/posts/new/preview", url_for(rs, { :controller => "subpath_books", :action => "preview" }) end def test_failed_constraints_raises_exception_with_violated_constraints @@ -574,9 +592,8 @@ class LegacyRouteSetTests < Test::Unit::TestCase match 'foos/:id' => 'foos#show', :as => 'foo_with_requirement', :constraints => { :id => /\d+/ } end - x = setup_for_named_route assert_raise(ActionController::RoutingError) do - x.send(:foo_with_requirement_url, "I am Against the constraints") + setup_for_named_route.send(:foo_with_requirement_url, "I am Against the constraints") end end @@ -606,11 +623,12 @@ class LegacyRouteSetTests < Test::Unit::TestCase assert_not_nil hash assert_equal %w(cc ac), [hash[:controller], hash[:action]] - end end class RouteSetTest < ActiveSupport::TestCase + include RoutingTestHelpers + def set @set ||= ROUTING::RouteSet.new end @@ -657,7 +675,8 @@ class RouteSetTest < ActiveSupport::TestCase match ':controller/:action/:id.:format' match ':controller/:action/:id' end - assert_equal "/foo/bar/15?this=hello", set.generate(:controller => "foo", :action => "bar", :id => 15, :this => "hello") + assert_equal "/foo/bar/15?this=hello", + url_for(set, { :controller => "foo", :action => "bar", :id => 15, :this => "hello" }) end def test_extra_keys_not_first @@ -742,7 +761,7 @@ class RouteSetTest < ActiveSupport::TestCase assert_equal "http://test.host/admin/users", controller.send(:users_url) assert_equal '/admin/users', controller.send(:users_path) - assert_equal '/admin/users', set.generate(controller.send(:hash_for_users_url), {:controller => 'users', :action => 'index'}) + assert_equal '/admin/users', url_for(set, controller.send(:hash_for_users_url), { :controller => 'users', :action => 'index' }) end def test_named_route_url_method_with_anchor @@ -813,8 +832,8 @@ class RouteSetTest < ActiveSupport::TestCase assert_equal 1, set.routes.size - assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10) - assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10) + assert_equal '/users/show/10', url_for(set, { :controller => 'users', :action => 'show', :id => 10 }) + assert_equal '/users/index/10', url_for(set, { :controller => 'users', :id => 10 }) assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10')) assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10/')) @@ -992,7 +1011,7 @@ class RouteSetTest < ActiveSupport::TestCase match "/people/list", :controller => "people", :action => "list" end - url = set.generate(:controller => "people", :action => "list") + url = url_for(set, { :controller => "people", :action => "list" }) assert_equal "/people/list", url end @@ -1057,8 +1076,9 @@ class RouteSetTest < ActiveSupport::TestCase def test_generate_changes_controller_module set.draw { match ':controller/:action/:id' } current = { :controller => "bling/bloop", :action => "bap", :id => 9 } - url = set.generate({:controller => "foo/bar", :action => "baz", :id => 7}, current) - assert_equal "/foo/bar/baz/7", url + + assert_equal "/foo/bar/baz/7", + url_for(set, { :controller => "foo/bar", :action => "baz", :id => 7 }, current) end def test_id_is_sticky_when_it_ought_to_be @@ -1066,7 +1086,7 @@ class RouteSetTest < ActiveSupport::TestCase match ':controller/:id/:action' end - url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"}) + url = url_for(set, { :action => "destroy" }, { :controller => "people", :action => "show", :id => "7" }) assert_equal "/people/7/destroy", url end @@ -1076,8 +1096,9 @@ class RouteSetTest < ActiveSupport::TestCase match ':controller/:action/:id' end - url = set.generate({:controller => "welcome", :action => "about"}, - {:controller => "welcome", :action => "get", :id => "7"}) + url = url_for(set, { :controller => "welcome", :action => "about" }, + { :controller => "welcome", :action => "get", :id => "7" }) + assert_equal "/about", url end @@ -1085,7 +1106,7 @@ class RouteSetTest < ActiveSupport::TestCase set.draw { match ':controller/:action/:id' } args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" } - assert_equal "/foo/bar/7?x=y", set.generate(args) + assert_equal "/foo/bar/7?x=y", url_for(set, args) assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args) assert_equal [:x], set.extra_keys(args) end @@ -1098,7 +1119,7 @@ class RouteSetTest < ActiveSupport::TestCase end args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" } - assert_equal "/my/foo/bar/7?x=y", set.generate(args) + assert_equal "/my/foo/bar/7?x=y", url_for(set, args) end def test_generate_with_blank_path_prefix @@ -1109,7 +1130,7 @@ class RouteSetTest < ActiveSupport::TestCase end args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" } - assert_equal "/foo/bar/7?x=y", set.generate(args) + assert_equal "/foo/bar/7?x=y", url_for(set, args) end def test_named_routes_are_never_relative_to_modules @@ -1119,10 +1140,10 @@ class RouteSetTest < ActiveSupport::TestCase match '/connection' => 'connection#index', :as => 'family_connection' end - url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'}) + url = url_for(set, { :controller => "connection" }, { :controller => 'connection/manage' }) assert_equal "/connection/connection", url - url = set.generate({:use_route => :family_connection, :controller => "connection"}, {:controller => 'connection/manage'}) + url = url_for(set, { :use_route => :family_connection, :controller => "connection" }, { :controller => 'connection/manage' }) assert_equal "/connection", url end @@ -1130,7 +1151,7 @@ class RouteSetTest < ActiveSupport::TestCase set.draw do match ':controller(/:action(/:id))' end - assert_equal '/books', set.generate( + assert_equal '/books', url_for(set, {:controller => 'books', :action => 'index'}, {:controller => 'books', :action => 'show', :id => '10'} ) @@ -1141,7 +1162,7 @@ class RouteSetTest < ActiveSupport::TestCase match 'show_weblog/:parameter' => 'weblog#show' match ':controller(/:action(/:id))' end - assert_equal '/weblog/edit?parameter=1', set.generate( + assert_equal '/weblog/edit?parameter=1', url_for(set, {:action => 'edit', :parameter => 1}, {:controller => 'weblog', :action => 'show', :parameter => 1} ) @@ -1152,12 +1173,12 @@ class RouteSetTest < ActiveSupport::TestCase match '/posts(.:format)' => 'posts#index' end - assert_equal '/posts', set.generate( + assert_equal '/posts', url_for(set, {:controller => 'posts'}, {:controller => 'posts', :action => 'index', :format => 'xml'} ) - assert_equal '/posts.xml', set.generate( + assert_equal '/posts.xml', url_for(set, {:controller => 'posts', :format => 'xml'}, {:controller => 'posts', :action => 'index', :format => 'xml'} ) @@ -1165,9 +1186,9 @@ class RouteSetTest < ActiveSupport::TestCase def test_expiry_determination_should_consider_values_with_to_param set.draw { match 'projects/:project_id/:controller/:action' } - assert_equal '/projects/1/weblog/show', set.generate( - {:action => 'show', :project_id => 1}, - {:controller => 'weblog', :action => 'show', :project_id => '1'}) + assert_equal '/projects/1/weblog/show', url_for(set, + { :action => 'show', :project_id => 1 }, + { :controller => 'weblog', :action => 'show', :project_id => '1' }) end def test_named_route_in_nested_resource @@ -1208,7 +1229,7 @@ class RouteSetTest < ActiveSupport::TestCase assert_raise ArgumentError do set.draw do match 'page/:name' => 'pages#show', - :constraints => {:name => /(david|jamis)/m} + :constraints => { :name => /(david|jamis)/m } end end end @@ -1217,18 +1238,18 @@ class RouteSetTest < ActiveSupport::TestCase assert_nothing_raised do set.draw do match 'page/:name' => 'pages#show', - :constraints => {:name => /(david|jamis)/i} + :constraints => { :name => /(david|jamis)/i } end end assert_nothing_raised do set.draw do match 'page/:name' => 'pages#show', - :constraints => {:name => / # Desperately overcommented regexp + :constraints => { :name => / # Desperately overcommented regexp ( #Either david #The Creator | #Or jamis #The Deployer - )/x} + )/x } end end end @@ -1251,12 +1272,12 @@ class RouteSetTest < ActiveSupport::TestCase :constraints => {:name => /(david|jamis)/i} end - url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'}) + url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'david' }) assert_equal "/page/david", url assert_raise ActionController::RoutingError do - url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'}) + url_for(set, { :controller => 'pages', :action => 'show', :name => 'davidjamis' }) end - url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'}) + url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' }) assert_equal "/page/JAMIS", url end @@ -1280,7 +1301,7 @@ class RouteSetTest < ActiveSupport::TestCase end end - def test_route_requirement_generate_with_xi_modifiers + def test_route_requirement_with_xi_modifiers set.draw do match 'page/:name' => 'pages#show', :constraints => {:name => / # Desperately overcommented regexp @@ -1291,21 +1312,11 @@ class RouteSetTest < ActiveSupport::TestCase )/xi} end - url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'}) - assert_equal "/page/JAMIS", url - end + assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, + set.recognize_path('/page/JAMIS')) - def test_route_requirement_recognize_with_xi_modifiers - set.draw do - match 'page/:name' => 'pages#show', - :constraints => {:name => / # Desperately overcommented regexp - ( #Either - david #The Creator - | #Or - jamis #The Deployer - )/xi} - end - assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS')) + assert_equal "/page/JAMIS", + url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' }) end def test_routes_with_symbols @@ -1323,8 +1334,8 @@ class RouteSetTest < ActiveSupport::TestCase match '/hello' => 'bar#index' end - assert_equal '/', set.generate(:controller => 'foo') - assert_equal '/hello', set.generate(:controller => 'bar') + assert_equal '/', url_for(set, { :controller => 'foo' }) + assert_equal '/hello', url_for(set, { :controller => 'bar' }) assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/')) assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/hello')) @@ -1335,7 +1346,7 @@ class RouteSetTest < ActiveSupport::TestCase match '/cars/:action/:person/:car/', :controller => 'cars' end - assert_equal '/cars/buy/1/2', set.generate(:controller => 'cars', :action => 'buy', :person => '1', :car => '2') + assert_equal '/cars/buy/1/2', url_for(set, { :controller => 'cars', :action => 'buy', :person => '1', :car => '2' }) assert_equal({:controller => "cars", :action => "buy", :person => "1", :car => "2"}, set.recognize_path('/cars/buy/1/2')) end @@ -1345,7 +1356,7 @@ class RouteSetTest < ActiveSupport::TestCase match '/books/:action.rss', :controller => 'books' end - assert_equal '/books/list.rss', set.generate(:controller => 'books', :action => 'list') + assert_equal '/books/list.rss', url_for(set, { :controller => 'books', :action => 'list' }) assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list.rss')) end @@ -1355,14 +1366,14 @@ class RouteSetTest < ActiveSupport::TestCase match '/books(/:action(.:format))', :controller => 'books' end - assert_equal '/books/list.rss', set.generate(:controller => 'books', :action => 'list', :format => 'rss') - assert_equal '/books/list.xml', set.generate(:controller => 'books', :action => 'list', :format => 'xml') - assert_equal '/books/list', set.generate(:controller => 'books', :action => 'list') - assert_equal '/books', set.generate(:controller => 'books', :action => 'index') + assert_equal '/books/list.rss', url_for(set, { :controller => 'books', :action => 'list', :format => 'rss' }) + assert_equal '/books/list.xml', url_for(set, { :controller => 'books', :action => 'list', :format => 'xml' }) + assert_equal '/books/list', url_for(set, { :controller => 'books', :action => 'list' }) + assert_equal '/books', url_for(set, { :controller => 'books', :action => 'index' }) assert_equal({:controller => "books", :action => "list", :format => "rss"}, set.recognize_path('/books/list.rss')) assert_equal({:controller => "books", :action => "list", :format => "xml"}, set.recognize_path('/books/list.xml')) - assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list')) + assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list')) assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books')) end @@ -1370,13 +1381,13 @@ class RouteSetTest < ActiveSupport::TestCase @set = nil set.draw { match("/:controller(/:action(/:id))") } - assert_equal '/content', set.generate(:controller => 'content', :action => 'index') - assert_equal '/content/list', set.generate(:controller => 'content', :action => 'list') - assert_equal '/content/show/1', set.generate(:controller => 'content', :action => 'show', :id => '1') + assert_equal '/content', url_for(set, { :controller => 'content', :action => 'index' }) + assert_equal '/content/list', url_for(set, { :controller => 'content', :action => 'list' }) + assert_equal '/content/show/1', url_for(set, { :controller => 'content', :action => 'show', :id => '1' }) assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content')) assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content/index')) - assert_equal({:controller => "content", :action => "list"}, set.recognize_path('/content/list')) + assert_equal({:controller => "content", :action => "list"}, set.recognize_path('/content/list')) assert_equal({:controller => "content", :action => "show", :id => "1"}, set.recognize_path('/content/show/1')) end @@ -1401,54 +1412,54 @@ class RouteSetTest < ActiveSupport::TestCase end def test_default_route_should_omit_default_action - assert_equal '/accounts', default_route_set.generate({:controller => 'accounts', :action => 'index'}) + assert_equal '/accounts', url_for(default_route_set, { :controller => 'accounts', :action => 'index' }) end def test_default_route_should_include_default_action_when_id_present - assert_equal '/accounts/index/20', default_route_set.generate({:controller => 'accounts', :action => 'index', :id => '20'}) + assert_equal '/accounts/index/20', url_for(default_route_set, { :controller => 'accounts', :action => 'index', :id => '20' }) end def test_default_route_should_work_with_action_but_no_id - assert_equal '/accounts/list_all', default_route_set.generate({:controller => 'accounts', :action => 'list_all'}) + assert_equal '/accounts/list_all', url_for(default_route_set, { :controller => 'accounts', :action => 'list_all' }) end def test_default_route_should_uri_escape_pluses expected = { :controller => 'pages', :action => 'show', :id => 'hello world' } assert_equal expected, default_route_set.recognize_path('/pages/show/hello%20world') - assert_equal '/pages/show/hello%20world', default_route_set.generate(expected, expected) + assert_equal '/pages/show/hello%20world', url_for(default_route_set, expected) expected[:id] = 'hello+world' assert_equal expected, default_route_set.recognize_path('/pages/show/hello+world') assert_equal expected, default_route_set.recognize_path('/pages/show/hello%2Bworld') - assert_equal '/pages/show/hello+world', default_route_set.generate(expected, expected) + assert_equal '/pages/show/hello+world', url_for(default_route_set, expected) end def test_build_empty_query_string - assert_uri_equal '/foo', default_route_set.generate({:controller => 'foo'}) + assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo' }) end def test_build_query_string_with_nil_value - assert_uri_equal '/foo', default_route_set.generate({:controller => 'foo', :x => nil}) + assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo', :x => nil }) end def test_simple_build_query_string - assert_uri_equal '/foo?x=1&y=2', default_route_set.generate({:controller => 'foo', :x => '1', :y => '2'}) + assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => '1', :y => '2' }) end def test_convert_ints_build_query_string - assert_uri_equal '/foo?x=1&y=2', default_route_set.generate({:controller => 'foo', :x => 1, :y => 2}) + assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => 1, :y => 2 }) end def test_escape_spaces_build_query_string - assert_uri_equal '/foo?x=hello+world&y=goodbye+world', default_route_set.generate({:controller => 'foo', :x => 'hello world', :y => 'goodbye world'}) + assert_uri_equal '/foo?x=hello+world&y=goodbye+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world', :y => 'goodbye world' }) end def test_expand_array_build_query_string - assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', default_route_set.generate({:controller => 'foo', :x => [1, 2]}) + assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', url_for(default_route_set, { :controller => 'foo', :x => [1, 2] }) end def test_escape_spaces_build_query_string_selected_keys - assert_uri_equal '/foo?x=hello+world', default_route_set.generate({:controller => 'foo', :x => 'hello world'}) + assert_uri_equal '/foo?x=hello+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world' }) end def test_generate_with_default_params @@ -1462,7 +1473,7 @@ class RouteSetTest < ActiveSupport::TestCase match ':controller/:action/:id' end - assert_equal '/ibocorp', set.generate({:controller => 'ibocorp', :action => "show", :page => 1}) + assert_equal '/ibocorp', url_for(set, { :controller => 'ibocorp', :action => "show", :page => 1 }) end def test_generate_with_optional_params_recalls_last_request @@ -1492,11 +1503,11 @@ class RouteSetTest < ActiveSupport::TestCase last_request = set.recognize_path("/blog/2006/07/28").freeze assert_equal({:controller => "blog", :action => "show_date", :year => "2006", :month => "07", :day => "28"}, last_request) - assert_equal("/blog/2006/07/25", set.generate({:day => 25}, last_request)) - assert_equal("/blog/2005", set.generate({:year => 2005}, last_request)) - assert_equal("/blog/show/123", set.generate({:action => "show" , :id => 123}, last_request)) - assert_equal("/blog/2006", set.generate({:year => 2006}, last_request)) - assert_equal("/blog/2006", set.generate({:year => 2006, :month => nil}, last_request)) + assert_equal("/blog/2006/07/25", url_for(set, { :day => 25 }, last_request)) + assert_equal("/blog/2005", url_for(set, { :year => 2005 }, last_request)) + assert_equal("/blog/show/123", url_for(set, { :action => "show" , :id => 123 }, last_request)) + assert_equal("/blog/2006", url_for(set, { :year => 2006 }, last_request)) + assert_equal("/blog/2006", url_for(set, { :year => 2006, :month => nil }, last_request)) end private @@ -1512,6 +1523,8 @@ class RouteSetTest < ActiveSupport::TestCase end class RackMountIntegrationTests < ActiveSupport::TestCase + include RoutingTestHelpers + Model = Struct.new(:to_param) Mapping = lambda { @@ -1647,111 +1660,111 @@ class RackMountIntegrationTests < ActiveSupport::TestCase end def test_generate - assert_equal '/admin/users', @routes.generate(:use_route => 'admin_users') - assert_equal '/admin/users', @routes.generate(:controller => 'admin/users') - assert_equal '/admin/users', @routes.generate(:controller => 'admin/users', :action => 'index') - assert_equal '/admin/users', @routes.generate({:action => 'index'}, {:controller => 'admin/users'}) - assert_equal '/admin/users', @routes.generate({:controller => 'users', :action => 'index'}, {:controller => 'admin/accounts'}) - assert_equal '/people', @routes.generate({:controller => '/people', :action => 'index'}, {:controller => 'admin/accounts'}) - - assert_equal '/admin/posts', @routes.generate({:controller => 'admin/posts'}) - assert_equal '/admin/posts/new', @routes.generate({:controller => 'admin/posts', :action => 'new'}) - - assert_equal '/blog/2009', @routes.generate(:controller => 'posts', :action => 'show_date', :year => 2009) - assert_equal '/blog/2009/1', @routes.generate(:controller => 'posts', :action => 'show_date', :year => 2009, :month => 1) - assert_equal '/blog/2009/1/1', @routes.generate(:controller => 'posts', :action => 'show_date', :year => 2009, :month => 1, :day => 1) - - assert_equal '/archive/2010', @routes.generate(:controller => 'archive', :action => 'index', :year => '2010') - assert_equal '/archive', @routes.generate(:controller => 'archive', :action => 'index') - assert_equal '/archive?year=january', @routes.generate(:controller => 'archive', :action => 'index', :year => 'january') - - assert_equal '/people', @routes.generate(:controller => 'people', :action => 'index') - assert_equal '/people', @routes.generate({:action => 'index'}, {:controller => 'people'}) - assert_equal '/people', @routes.generate({:action => 'index'}, {:controller => 'people', :action => 'show', :id => '1'}) - assert_equal '/people', @routes.generate({:controller => 'people', :action => 'index'}, {:controller => 'people', :action => 'show', :id => '1'}) - assert_equal '/people', @routes.generate({}, {:controller => 'people', :action => 'index'}) - assert_equal '/people/1', @routes.generate({:controller => 'people', :action => 'show'}, {:controller => 'people', :action => 'show', :id => '1'}) - assert_equal '/people/new', @routes.generate(:use_route => 'new_person') - assert_equal '/people/new', @routes.generate(:controller => 'people', :action => 'new') - assert_equal '/people/1', @routes.generate(:use_route => 'person', :id => '1') - assert_equal '/people/1', @routes.generate(:controller => 'people', :action => 'show', :id => '1') - assert_equal '/people/1.xml', @routes.generate(:controller => 'people', :action => 'show', :id => '1', :format => 'xml') - assert_equal '/people/1', @routes.generate(:controller => 'people', :action => 'show', :id => 1) - assert_equal '/people/1', @routes.generate(:controller => 'people', :action => 'show', :id => Model.new('1')) - assert_equal '/people/1', @routes.generate({:action => 'show', :id => '1'}, {:controller => 'people', :action => 'index'}) - assert_equal '/people/1', @routes.generate({:action => 'show', :id => 1}, {:controller => 'people', :action => 'show', :id => '1'}) - assert_equal '/people', @routes.generate({:controller => 'people', :action => 'index'}, {:controller => 'people', :action => 'show', :id => '1'}) - assert_equal '/people/1', @routes.generate({}, {:controller => 'people', :action => 'show', :id => '1'}) - assert_equal '/people/1', @routes.generate({:controller => 'people', :action => 'show'}, {:controller => 'people', :action => 'index', :id => '1'}) - assert_equal '/people/1/edit', @routes.generate(:controller => 'people', :action => 'edit', :id => '1') - assert_equal '/people/1/edit.xml', @routes.generate(:controller => 'people', :action => 'edit', :id => '1', :format => 'xml') - assert_equal '/people/1/edit', @routes.generate(:use_route => 'edit_person', :id => '1') - assert_equal '/people/1?legacy=true', @routes.generate(:controller => 'people', :action => 'show', :id => '1', :legacy => 'true') - assert_equal '/people?legacy=true', @routes.generate(:controller => 'people', :action => 'index', :legacy => 'true') - - assert_equal '/id_default/2', @routes.generate(:controller => 'foo', :action => 'id_default', :id => '2') - assert_equal '/id_default', @routes.generate(:controller => 'foo', :action => 'id_default', :id => '1') - assert_equal '/id_default', @routes.generate(:controller => 'foo', :action => 'id_default', :id => 1) - assert_equal '/id_default', @routes.generate(:controller => 'foo', :action => 'id_default') - assert_equal '/optional/bar', @routes.generate(:controller => 'posts', :action => 'index', :optional => 'bar') - assert_equal '/posts', @routes.generate(:controller => 'posts', :action => 'index') - - assert_equal '/project', @routes.generate({:controller => 'project', :action => 'index'}) - assert_equal '/projects/1', @routes.generate({:controller => 'project', :action => 'index', :project_id => '1'}) - assert_equal '/projects/1', @routes.generate({:controller => 'project', :action => 'index'}, {:project_id => '1'}) - assert_raise(ActionController::RoutingError) { @routes.generate({:use_route => 'project', :controller => 'project', :action => 'index'}) } - assert_equal '/projects/1', @routes.generate({:use_route => 'project', :controller => 'project', :action => 'index', :project_id => '1'}) - assert_equal '/projects/1', @routes.generate({:use_route => 'project', :controller => 'project', :action => 'index'}, {:project_id => '1'}) - - assert_equal '/clients', @routes.generate(:controller => 'projects', :action => 'index') - assert_equal '/clients?project_id=1', @routes.generate(:controller => 'projects', :action => 'index', :project_id => '1') - assert_equal '/clients', @routes.generate({:controller => 'projects', :action => 'index'}, {:project_id => '1'}) - assert_equal '/clients', @routes.generate({:action => 'index'}, {:controller => 'projects', :action => 'index', :project_id => '1'}) - - assert_equal '/comment/20', @routes.generate({:id => 20}, {:controller => 'comments', :action => 'show'}) - assert_equal '/comment/20', @routes.generate(:controller => 'comments', :id => 20, :action => 'show') - assert_equal '/comments/boo', @routes.generate(:controller => 'comments', :action => 'boo') - - assert_equal '/ws/posts/show/1', @routes.generate(:controller => 'posts', :action => 'show', :id => '1', :ws => true) - assert_equal '/ws/posts', @routes.generate(:controller => 'posts', :action => 'index', :ws => true) - - assert_equal '/account', @routes.generate(:controller => 'account', :action => 'subscription') - assert_equal '/account/billing', @routes.generate(:controller => 'account', :action => 'billing') - - assert_equal '/pages/1/notes/show/1', @routes.generate(:page_id => '1', :controller => 'notes', :action => 'show', :id => '1') - assert_equal '/pages/1/notes/list', @routes.generate(:page_id => '1', :controller => 'notes', :action => 'list') - assert_equal '/pages/1/notes', @routes.generate(:page_id => '1', :controller => 'notes', :action => 'index') - assert_equal '/pages/1/notes', @routes.generate(:page_id => '1', :controller => 'notes') - assert_equal '/notes', @routes.generate(:page_id => nil, :controller => 'notes') - assert_equal '/notes', @routes.generate(:controller => 'notes') - assert_equal '/notes/print', @routes.generate(:controller => 'notes', :action => 'print') - assert_equal '/notes/print', @routes.generate({}, {:controller => 'notes', :action => 'print'}) - - assert_equal '/notes/index/1', @routes.generate({:controller => 'notes'}, {:controller => 'notes', :id => '1'}) - assert_equal '/notes/index/1', @routes.generate({:controller => 'notes'}, {:controller => 'notes', :id => '1', :foo => 'bar'}) - assert_equal '/notes/index/1', @routes.generate({:controller => 'notes'}, {:controller => 'notes', :id => '1'}) - assert_equal '/notes/index/1', @routes.generate({:action => 'index'}, {:controller => 'notes', :id => '1'}) - assert_equal '/notes/index/1', @routes.generate({}, {:controller => 'notes', :id => '1'}) - assert_equal '/notes/show/1', @routes.generate({}, {:controller => 'notes', :action => 'show', :id => '1'}) - assert_equal '/notes/index/1', @routes.generate({:controller => 'notes', :id => '1'}, {:foo => 'bar'}) - assert_equal '/posts', @routes.generate({:controller => 'posts'}, {:controller => 'notes', :action => 'show', :id => '1'}) - assert_equal '/notes/list', @routes.generate({:action => 'list'}, {:controller => 'notes', :action => 'show', :id => '1'}) - - assert_equal '/posts/ping', @routes.generate(:controller => 'posts', :action => 'ping') - assert_equal '/posts/show/1', @routes.generate(:controller => 'posts', :action => 'show', :id => '1') - assert_equal '/posts', @routes.generate(:controller => 'posts') - assert_equal '/posts', @routes.generate(:controller => 'posts', :action => 'index') - assert_equal '/posts', @routes.generate({:controller => 'posts'}, {:controller => 'posts', :action => 'index'}) - assert_equal '/posts/create', @routes.generate({:action => 'create'}, {:controller => 'posts'}) - assert_equal '/posts?foo=bar', @routes.generate(:controller => 'posts', :foo => 'bar') - assert_equal '/posts?foo%5B%5D=bar&foo%5B%5D=baz', @routes.generate(:controller => 'posts', :foo => ['bar', 'baz']) - assert_equal '/posts?page=2', @routes.generate(:controller => 'posts', :page => 2) - assert_equal '/posts?q%5Bfoo%5D%5Ba%5D=b', @routes.generate(:controller => 'posts', :q => { :foo => { :a => 'b'}}) - - assert_equal '/news.rss', @routes.generate(:controller => 'news', :action => 'index', :format => 'rss') - - - assert_raise(ActionController::RoutingError) { @routes.generate({:action => 'index'}) } + assert_equal '/admin/users', url_for(@routes, { :use_route => 'admin_users' }) + assert_equal '/admin/users', url_for(@routes, { :controller => 'admin/users' }) + assert_equal '/admin/users', url_for(@routes, { :controller => 'admin/users', :action => 'index' }) + assert_equal '/admin/users', url_for(@routes, { :action => 'index' }, { :controller => 'admin/users' }) + assert_equal '/admin/users', url_for(@routes, { :controller => 'users', :action => 'index' }, { :controller => 'admin/accounts' }) + assert_equal '/people', url_for(@routes, { :controller => '/people', :action => 'index' }, { :controller => 'admin/accounts' }) + + assert_equal '/admin/posts', url_for(@routes, { :controller => 'admin/posts' }) + assert_equal '/admin/posts/new', url_for(@routes, { :controller => 'admin/posts', :action => 'new' }) + + assert_equal '/blog/2009', url_for(@routes, { :controller => 'posts', :action => 'show_date', :year => 2009 }) + assert_equal '/blog/2009/1', url_for(@routes, { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1 }) + assert_equal '/blog/2009/1/1', url_for(@routes, { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1, :day => 1 }) + + assert_equal '/archive/2010', url_for(@routes, { :controller => 'archive', :action => 'index', :year => '2010' }) + assert_equal '/archive', url_for(@routes, { :controller => 'archive', :action => 'index' }) + assert_equal '/archive?year=january', url_for(@routes, { :controller => 'archive', :action => 'index', :year => 'january' }) + + assert_equal '/people', url_for(@routes, { :controller => 'people', :action => 'index' }) + assert_equal '/people', url_for(@routes, { :action => 'index' }, { :controller => 'people' }) + assert_equal '/people', url_for(@routes, { :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }) + assert_equal '/people', url_for(@routes, { :controller => 'people', :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }) + assert_equal '/people', url_for(@routes, {}, { :controller => 'people', :action => 'index' }) + assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show' }, { :controller => 'people', :action => 'show', :id => '1' }) + assert_equal '/people/new', url_for(@routes, { :use_route => 'new_person' }) + assert_equal '/people/new', url_for(@routes, { :controller => 'people', :action => 'new' }) + assert_equal '/people/1', url_for(@routes, { :use_route => 'person', :id => '1' }) + assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show', :id => '1' }) + assert_equal '/people/1.xml', url_for(@routes, { :controller => 'people', :action => 'show', :id => '1', :format => 'xml' }) + assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show', :id => 1 }) + assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show', :id => Model.new('1') }) + assert_equal '/people/1', url_for(@routes, { :action => 'show', :id => '1' }, { :controller => 'people', :action => 'index' }) + assert_equal '/people/1', url_for(@routes, { :action => 'show', :id => 1 }, { :controller => 'people', :action => 'show', :id => '1' }) + assert_equal '/people', url_for(@routes, { :controller => 'people', :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }) + assert_equal '/people/1', url_for(@routes, {}, { :controller => 'people', :action => 'show', :id => '1' }) + assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show' }, { :controller => 'people', :action => 'index', :id => '1' }) + assert_equal '/people/1/edit', url_for(@routes, { :controller => 'people', :action => 'edit', :id => '1' }) + assert_equal '/people/1/edit.xml', url_for(@routes, { :controller => 'people', :action => 'edit', :id => '1', :format => 'xml' }) + assert_equal '/people/1/edit', url_for(@routes, { :use_route => 'edit_person', :id => '1' }) + assert_equal '/people/1?legacy=true', url_for(@routes, { :controller => 'people', :action => 'show', :id => '1', :legacy => 'true' }) + assert_equal '/people?legacy=true', url_for(@routes, { :controller => 'people', :action => 'index', :legacy => 'true' }) + + assert_equal '/id_default/2', url_for(@routes, { :controller => 'foo', :action => 'id_default', :id => '2' }) + assert_equal '/id_default', url_for(@routes, { :controller => 'foo', :action => 'id_default', :id => '1' }) + assert_equal '/id_default', url_for(@routes, { :controller => 'foo', :action => 'id_default', :id => 1 }) + assert_equal '/id_default', url_for(@routes, { :controller => 'foo', :action => 'id_default' }) + assert_equal '/optional/bar', url_for(@routes, { :controller => 'posts', :action => 'index', :optional => 'bar' }) + assert_equal '/posts', url_for(@routes, { :controller => 'posts', :action => 'index' }) + + assert_equal '/project', url_for(@routes, { :controller => 'project', :action => 'index' }) + assert_equal '/projects/1', url_for(@routes, { :controller => 'project', :action => 'index', :project_id => '1' }) + assert_equal '/projects/1', url_for(@routes, { :controller => 'project', :action => 'index'}, {:project_id => '1' }) + assert_raise(ActionController::RoutingError) { url_for(@routes, { :use_route => 'project', :controller => 'project', :action => 'index' }) } + assert_equal '/projects/1', url_for(@routes, { :use_route => 'project', :controller => 'project', :action => 'index', :project_id => '1' }) + assert_equal '/projects/1', url_for(@routes, { :use_route => 'project', :controller => 'project', :action => 'index' }, { :project_id => '1' }) + + assert_equal '/clients', url_for(@routes, { :controller => 'projects', :action => 'index' }) + assert_equal '/clients?project_id=1', url_for(@routes, { :controller => 'projects', :action => 'index', :project_id => '1' }) + assert_equal '/clients', url_for(@routes, { :controller => 'projects', :action => 'index' }, { :project_id => '1' }) + assert_equal '/clients', url_for(@routes, { :action => 'index' }, { :controller => 'projects', :action => 'index', :project_id => '1' }) + + assert_equal '/comment/20', url_for(@routes, { :id => 20 }, { :controller => 'comments', :action => 'show' }) + assert_equal '/comment/20', url_for(@routes, { :controller => 'comments', :id => 20, :action => 'show' }) + assert_equal '/comments/boo', url_for(@routes, { :controller => 'comments', :action => 'boo' }) + + assert_equal '/ws/posts/show/1', url_for(@routes, { :controller => 'posts', :action => 'show', :id => '1', :ws => true }) + assert_equal '/ws/posts', url_for(@routes, { :controller => 'posts', :action => 'index', :ws => true }) + + assert_equal '/account', url_for(@routes, { :controller => 'account', :action => 'subscription' }) + assert_equal '/account/billing', url_for(@routes, { :controller => 'account', :action => 'billing' }) + + assert_equal '/pages/1/notes/show/1', url_for(@routes, { :page_id => '1', :controller => 'notes', :action => 'show', :id => '1' }) + assert_equal '/pages/1/notes/list', url_for(@routes, { :page_id => '1', :controller => 'notes', :action => 'list' }) + assert_equal '/pages/1/notes', url_for(@routes, { :page_id => '1', :controller => 'notes', :action => 'index' }) + assert_equal '/pages/1/notes', url_for(@routes, { :page_id => '1', :controller => 'notes' }) + assert_equal '/notes', url_for(@routes, { :page_id => nil, :controller => 'notes' }) + assert_equal '/notes', url_for(@routes, { :controller => 'notes' }) + assert_equal '/notes/print', url_for(@routes, { :controller => 'notes', :action => 'print' }) + assert_equal '/notes/print', url_for(@routes, {}, { :controller => 'notes', :action => 'print' }) + + assert_equal '/notes/index/1', url_for(@routes, { :controller => 'notes' }, { :controller => 'notes', :id => '1' }) + assert_equal '/notes/index/1', url_for(@routes, { :controller => 'notes' }, { :controller => 'notes', :id => '1', :foo => 'bar' }) + assert_equal '/notes/index/1', url_for(@routes, { :controller => 'notes' }, { :controller => 'notes', :id => '1' }) + assert_equal '/notes/index/1', url_for(@routes, { :action => 'index' }, { :controller => 'notes', :id => '1' }) + assert_equal '/notes/index/1', url_for(@routes, {}, { :controller => 'notes', :id => '1' }) + assert_equal '/notes/show/1', url_for(@routes, {}, { :controller => 'notes', :action => 'show', :id => '1' }) + assert_equal '/notes/index/1', url_for(@routes, { :controller => 'notes', :id => '1' }, { :foo => 'bar' }) + assert_equal '/posts', url_for(@routes, { :controller => 'posts' }, { :controller => 'notes', :action => 'show', :id => '1' }) + assert_equal '/notes/list', url_for(@routes, { :action => 'list' }, { :controller => 'notes', :action => 'show', :id => '1' }) + + assert_equal '/posts/ping', url_for(@routes, { :controller => 'posts', :action => 'ping' }) + assert_equal '/posts/show/1', url_for(@routes, { :controller => 'posts', :action => 'show', :id => '1' }) + assert_equal '/posts', url_for(@routes, { :controller => 'posts' }) + assert_equal '/posts', url_for(@routes, { :controller => 'posts', :action => 'index' }) + assert_equal '/posts', url_for(@routes, { :controller => 'posts' }, { :controller => 'posts', :action => 'index' }) + assert_equal '/posts/create', url_for(@routes, { :action => 'create' }, { :controller => 'posts' }) + assert_equal '/posts?foo=bar', url_for(@routes, { :controller => 'posts', :foo => 'bar' }) + assert_equal '/posts?foo%5B%5D=bar&foo%5B%5D=baz', url_for(@routes, { :controller => 'posts', :foo => ['bar', 'baz'] }) + assert_equal '/posts?page=2', url_for(@routes, { :controller => 'posts', :page => 2 }) + assert_equal '/posts?q%5Bfoo%5D%5Ba%5D=b', url_for(@routes, { :controller => 'posts', :q => { :foo => { :a => 'b'}} }) + + assert_equal '/news.rss', url_for(@routes, { :controller => 'news', :action => 'index', :format => 'rss' }) + + + assert_raise(ActionController::RoutingError) { url_for(@routes, { :action => 'index' }) } end def test_generate_extras diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 8f672c1149..75b674ec1a 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -1,6 +1,31 @@ require 'abstract_unit' class RequestTest < ActiveSupport::TestCase + + def url_for(options = {}) + options.reverse_merge!(:host => 'www.example.com') + ActionDispatch::Http::URL.url_for(options) + end + + test "url_for class method" do + e = assert_raise(ArgumentError) { url_for(:host => nil) } + assert_match(/Please provide the :host parameter/, e.message) + + assert_equal '/books', url_for(:only_path => true, :path => '/books') + + assert_equal 'http://www.example.com', url_for + assert_equal 'http://api.example.com', url_for(:subdomain => 'api') + assert_equal 'http://www.ror.com', url_for(:domain => 'ror.com') + assert_equal 'http://api.ror.co.uk', url_for(:host => 'www.ror.co.uk', :subdomain => 'api', :tld_length => 2) + assert_equal 'http://www.example.com:8080', url_for(:port => 8080) + assert_equal 'https://www.example.com', url_for(:protocol => 'https') + assert_equal 'http://www.example.com/docs', url_for(:path => '/docs') + assert_equal 'http://www.example.com#signup', url_for(:anchor => 'signup') + assert_equal 'http://www.example.com/', url_for(:trailing_slash => true) + assert_equal 'http://dhh:supersecret@www.example.com', url_for(:user => 'dhh', :password => 'supersecret') + assert_equal 'http://www.example.com?search=books', url_for(:params => { :search => 'books' }) + end + test "remote ip" do request = stub_request 'REMOTE_ADDR' => '1.2.3.4' assert_equal '1.2.3.4', request.remote_ip diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index bbd010ea6d..74420317c7 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -13,6 +13,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + class YoutubeFavoritesRedirector + def self.call(params, request) + "http://www.youtube.com/watch?v=#{params[:youtube_id]}" + end + end + stub_controllers do |routes| Routes = routes Routes.draw do @@ -54,6 +60,13 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match 'account/login', :to => redirect("/login") match 'secure', :to => redirect("/secure/login") + match 'mobile', :to => redirect(:subdomain => 'mobile') + match 'documentation', :to => redirect(:domain => 'example-documentation.com', :path => '') + match 'new_documentation', :to => redirect(:path => '/documentation/new') + match 'super_new_documentation', :to => redirect(:host => 'super-docs.com') + + match 'youtube_favorites/:youtube_id/:name', :to => redirect(YoutubeFavoritesRedirector) + constraints(lambda { |req| true }) do match 'account/overview' end @@ -667,6 +680,41 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_redirect_hash_with_subdomain + with_test_routes do + get '/mobile' + verify_redirect 'http://mobile.example.com/mobile' + end + end + + def test_redirect_hash_with_domain_and_path + with_test_routes do + get '/documentation' + verify_redirect 'http://www.example-documentation.com' + end + end + + def test_redirect_hash_with_path + with_test_routes do + get '/new_documentation' + verify_redirect 'http://www.example.com/documentation/new' + end + end + + def test_redirect_hash_with_host + with_test_routes do + get '/super_new_documentation?section=top' + verify_redirect 'http://super-docs.com/super_new_documentation?section=top' + end + end + + def test_redirect_class + with_test_routes do + get '/youtube_favorites/oHg5SJYRHA0/rick-rolld' + verify_redirect 'http://www.youtube.com/watch?v=oHg5SJYRHA0' + end + end + def test_openid with_test_routes do get '/openid/login' -- cgit v1.2.3 From 1e26bda0959c313ce5c1816bf4958b542050e5e2 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Tue, 30 Nov 2010 17:55:33 +0100 Subject: Added documentation explaining the new additional supported syntaxes for the routing redirect method, a small changelog note, and two extra tests for path interpolation when using the hash option syntax. --- actionpack/CHANGELOG | 2 ++ .../lib/action_dispatch/routing/redirection.rb | 29 ++++++++++++++++++++++ actionpack/test/dispatch/routing_test.rb | 17 +++++++++++++ 3 files changed, 48 insertions(+) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 74d017cc3d..9b292cca69 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.1.0 (unreleased)* +* The redirect route method now also accepts a hash of options which will only change the parts of the url in question, or an object which responds to call, allowing for redirects to be reused (check the documentation for examples). [Josh Kalderimis] + * Added config.action_controller.include_all_helpers. By default 'helper :all' is done in ActionController::Base, which includes all the helpers by default. Setting include_all_helpers to false will result in including only application_helper and helper corresponding to controller (like foo_helper for foo_controller). [Piotr Sarnacki] * Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options: diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index d9c9a400a7..804991ad5f 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -7,6 +7,35 @@ module ActionDispatch # Redirect any path to another path: # # match "/stories" => redirect("/posts") + # + # You can also use interpolation in the supplied redirect argument: + # + # match 'docs/:article', :to => redirect('/wiki/%{article}') + # + # Alternatively you can use one of the other syntaxes: + # + # The block version of redirect allows for the easy encapsulation of any logic associated with + # the redirect in question. Either the params and request are supplied as arguments, or just + # params, depending of how many arguments your block accepts. A string is required as a + # return value. + # + # match 'jokes/:number', :to => redirect do |params, request| + # path = (params[:number].to_i.even? ? "/wheres-the-beef" : "/i-love-lamp") + # "http://#{request.host_with_port}/#{path}" + # end + # + # The options version of redirect allows you to supply only the parts of the url which need + # to change, it also supports interpolation of the path similar to the first example. + # + # match 'stores/:name', :to => redirect(:subdomain => 'stores', :path => '/%{name}') + # match 'stores/:name(*all)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{all}') + # + # Finally, an object which responds to call can be supplied to redirect, allowing you to reuse + # common redirect routes. The call method must accept two arguments, params and request, and return + # a string. + # + # match 'accounts/:name' => redirect(SubdomainRedirector.new('api')) + # def redirect(*args, &block) options = args.last.is_a?(Hash) ? args.pop : {} status = options.delete(:status) || 301 diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 74420317c7..4bf7880294 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -65,6 +65,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match 'new_documentation', :to => redirect(:path => '/documentation/new') match 'super_new_documentation', :to => redirect(:host => 'super-docs.com') + match 'stores/:name', :to => redirect(:subdomain => 'stores', :path => '/%{name}') + match 'stores/:name(*rest)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{rest}') + match 'youtube_favorites/:youtube_id/:name', :to => redirect(YoutubeFavoritesRedirector) constraints(lambda { |req| true }) do @@ -708,6 +711,20 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_redirect_hash_path_substitution + with_test_routes do + get '/stores/iernest' + verify_redirect 'http://stores.example.com/iernest' + end + end + + def test_redirect_hash_path_substitution_with_catch_all + with_test_routes do + get '/stores/iernest/products' + verify_redirect 'http://stores.example.com/iernest/products' + end + end + def test_redirect_class with_test_routes do get '/youtube_favorites/oHg5SJYRHA0/rick-rolld' -- cgit v1.2.3 From 831a2342c69f1d602aca9e894bffa4f6dbf614ed Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 30 Nov 2010 20:04:31 -0800 Subject: just use alias --- actionpack/lib/action_dispatch/testing/integration.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 8fe74c3c80..5c6416a19e 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -235,9 +235,7 @@ module ActionDispatch # Set the host name to use in the next request. # # session.host! "www.example.com" - def host!(name) - @host = name - end + alias :host! :host= private def _mock_session -- cgit v1.2.3 From ba63c0a9b58691adeca645977828ee918107208d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 1 Dec 2010 11:22:48 +0100 Subject: Deprecate handler_class_for_extension as template handlers can be any Ruby object, not necessarily a class. --- actionpack/lib/action_view/renderer/template_renderer.rb | 2 +- actionpack/lib/action_view/template/handlers.rb | 8 +++++++- actionpack/lib/action_view/template/resolver.rb | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb index 6912acee31..ece3f621b6 100644 --- a/actionpack/lib/action_view/renderer/template_renderer.rb +++ b/actionpack/lib/action_view/renderer/template_renderer.rb @@ -45,7 +45,7 @@ module ActionView elsif options.key?(:file) with_fallbacks { find_template(options[:file], options[:prefix], false, keys) } elsif options.key?(:inline) - handler = Template.handler_class_for_extension(options[:type] || "erb") + handler = Template.handler_for_extension(options[:type] || "erb") Template.new(options[:inline], "inline template", handler, :locals => keys) elsif options.key?(:template) options[:template].respond_to?(:render) ? diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index 60347e2a95..4438199497 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -44,7 +44,13 @@ module ActionView #:nodoc: end def handler_class_for_extension(extension) - (extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers + ActiveSupport::Deprecation.warn "handler_class_for_extension is deprecated. " << + "Please use handler_for_extension instead", caller + handler_for_extension(extension) + end + + def handler_for_extension(extension) + registered_template_handler(extension) || @@default_template_handlers end end end diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 7707dbcf98..9f15661669 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -129,7 +129,7 @@ module ActionView def extract_handler_and_format(path, default_formats) pieces = File.basename(path).split(".") pieces.shift - handler = Template.handler_class_for_extension(pieces.pop) + handler = Template.handler_for_extension(pieces.pop) format = pieces.last && Mime[pieces.last] [handler, format] end -- cgit v1.2.3 From 226ea0e9e817a2e449d989d925c36cf6a4cfd67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 3 Dec 2010 13:27:43 +0100 Subject: Wrap everything in class << self. --- actionpack/lib/action_dispatch/http/url.rb | 79 ++++++++++++++---------------- 1 file changed, 37 insertions(+), 42 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index 51d4766282..796cd8c09b 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -4,55 +4,54 @@ module ActionDispatch mattr_accessor :tld_length self.tld_length = 1 - def self.extract_domain(host, tld_length = @@tld_length) - return nil unless named_host?(host) - - host.split('.').last(1 + tld_length).join('.') - end - - def self.extract_subdomains(host, tld_length = @@tld_length) - return [] unless named_host?(host) - parts = host.split('.') - parts[0..-(tld_length+2)] - end - - def self.extract_subdomain(host, tld_length = @@tld_length) - extract_subdomains(host, tld_length).join('.') - end + class << self + def extract_domain(host, tld_length = @@tld_length) + return nil unless named_host?(host) + host.split('.').last(1 + tld_length).join('.') + end - def self.named_host?(host) - !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host)) - end + def extract_subdomains(host, tld_length = @@tld_length) + return [] unless named_host?(host) + parts = host.split('.') + parts[0..-(tld_length+2)] + end - def self.url_for(options = {}) - unless options[:host].present? || options[:only_path].present? - raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' + def extract_subdomain(host, tld_length = @@tld_length) + extract_subdomains(host, tld_length).join('.') end - rewritten_url = "" + def url_for(options = {}) + unless options[:host].present? || options[:only_path].present? + raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' + end - unless options[:only_path] - rewritten_url << (options[:protocol] || "http") - rewritten_url << "://" unless rewritten_url.match("://") - rewritten_url << rewrite_authentication(options) - rewritten_url << host_or_subdomain_and_domain(options) - rewritten_url << ":#{options.delete(:port)}" if options[:port] - end + rewritten_url = "" - path = options.delete(:path) || '' + unless options[:only_path] + rewritten_url << (options[:protocol] || "http") + rewritten_url << "://" unless rewritten_url.match("://") + rewritten_url << rewrite_authentication(options) + rewritten_url << host_or_subdomain_and_domain(options) + rewritten_url << ":#{options.delete(:port)}" if options[:port] + end - params = options[:params] || {} - params.reject! {|k,v| !v } + path = options.delete(:path) || '' - rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) - rewritten_url << "?#{params.to_query}" unless params.empty? - rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor] - rewritten_url - end + params = options[:params] || {} + params.reject! {|k,v| !v } + + rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) + rewritten_url << "?#{params.to_query}" unless params.empty? + rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor] + rewritten_url + end - class << self private + def named_host?(host) + !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host)) + end + def rewrite_authentication(options) if options[:user] && options[:password] "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@" @@ -72,11 +71,8 @@ module ActionDispatch host << (options[:domain] || extract_domain(options[:host], tld_length)) host end - end - - # Returns the complete URL used for this request. def url protocol + host_with_port + fullpath @@ -168,7 +164,6 @@ module ActionDispatch def subdomain(tld_length = @@tld_length) subdomains(tld_length) end - end end end -- cgit v1.2.3 From 7ffd5daa7fe1fd805fd071d40dfad1773299c7d1 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 14 Nov 2010 18:30:09 +0100 Subject: bump i18n gem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/actionpack.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 44967631ff..b7d1d8c2af 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -23,7 +23,7 @@ Gem::Specification.new do |s| s.add_dependency('activemodel', version) s.add_dependency('rack-cache', '~> 0.5.3') s.add_dependency('builder', '~> 3.0.0') - s.add_dependency('i18n', '~> 0.4.2') + s.add_dependency('i18n', '~> 0.5.0') s.add_dependency('rack', '~> 1.2.1') s.add_dependency('rack-test', '~> 0.5.6') s.add_dependency('rack-mount', '~> 0.6.13') -- cgit v1.2.3 From 896e25e994e272a1cb485d9a850501b488992cb2 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 14 Nov 2010 18:46:40 +0100 Subject: Make TranslationHelper#translate use the :rescue_format option in I18n 0.5.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't catch exceptions here. Instead only declare that we want exceptions to be rescued as :html, but also let users configure reactions to exceptions in I18n. Signed-off-by: José Valim --- .../lib/action_view/helpers/translation_helper.rb | 32 ++++++++--- .../test/fixtures/test/scoped_translation.erb | 1 - actionpack/test/fixtures/test/translation.erb | 1 - .../test/fixtures/translations/templates/array.erb | 1 + .../test/fixtures/translations/templates/found.erb | 1 + .../fixtures/translations/templates/missing.erb | 1 + .../test/template/translation_helper_test.rb | 67 +++++++++++++--------- 7 files changed, 68 insertions(+), 36 deletions(-) delete mode 100644 actionpack/test/fixtures/test/scoped_translation.erb delete mode 100644 actionpack/test/fixtures/test/translation.erb create mode 100644 actionpack/test/fixtures/translations/templates/array.erb create mode 100644 actionpack/test/fixtures/translations/templates/found.erb create mode 100644 actionpack/test/fixtures/translations/templates/missing.erb (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index 8574ca6595..e7ec1df2c8 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -1,13 +1,33 @@ require 'action_view/helpers/tag_helper' +require 'i18n/exceptions' + +module I18n + class ExceptionHandler + include Module.new { + def call(exception, locale, key, options) + exception.is_a?(MissingTranslationData) ? super.html_safe : super + end + } + end +end module ActionView # = Action View Translation Helpers module Helpers module TranslationHelper # Delegates to I18n#translate but also performs three additional functions. - # First, it'll catch MissingTranslationData exceptions and turn them into - # inline spans that contains the missing key, such that you can see in a - # view what is missing where. + # + # First, it'll pass the :rescue_format => :html option to I18n so that any caught + # MissingTranslationData exceptions will be turned into inline spans that + # + # * have a "translation-missing" class set, + # * contain the missing key as a title attribute and + # * a titleized version of the last key segment as a text. + # + # E.g. the value returned for a missing translation key :"blog.post.title" will be + # Title. + # This way your views will display rather reasonableful strings but it will still + # be easy to spot missing translations. # # Second, it'll scope the key by the current partial if the key starts # with a period. So if you call translate(".foo") from the @@ -24,15 +44,13 @@ module ActionView # naming convention helps to identify translations that include HTML tags so that # you know what kind of output to expect when you call translate in a template. def translate(key, options = {}) - translation = I18n.translate(scope_key_by_partial(key), options.merge!(:raise => true)) + options.merge!(:rescue_format => :html) unless options.key?(:rescue_format) + translation = I18n.translate(scope_key_by_partial(key), options) if html_safe_translation_key?(key) && translation.respond_to?(:html_safe) translation.html_safe else translation end - rescue I18n::MissingTranslationData => e - keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope]) - content_tag('span', keys.join(', '), :class => 'translation_missing') end alias :t :translate diff --git a/actionpack/test/fixtures/test/scoped_translation.erb b/actionpack/test/fixtures/test/scoped_translation.erb deleted file mode 100644 index 3be63ab3cc..0000000000 --- a/actionpack/test/fixtures/test/scoped_translation.erb +++ /dev/null @@ -1 +0,0 @@ -<%= t('.foo.bar').join %> \ No newline at end of file diff --git a/actionpack/test/fixtures/test/translation.erb b/actionpack/test/fixtures/test/translation.erb deleted file mode 100644 index 81a837d1ff..0000000000 --- a/actionpack/test/fixtures/test/translation.erb +++ /dev/null @@ -1 +0,0 @@ -<%= t('.helper') %> \ No newline at end of file diff --git a/actionpack/test/fixtures/translations/templates/array.erb b/actionpack/test/fixtures/translations/templates/array.erb new file mode 100644 index 0000000000..d86045a172 --- /dev/null +++ b/actionpack/test/fixtures/translations/templates/array.erb @@ -0,0 +1 @@ +<%= t('.foo.bar') %> diff --git a/actionpack/test/fixtures/translations/templates/found.erb b/actionpack/test/fixtures/translations/templates/found.erb new file mode 100644 index 0000000000..080c9c0aee --- /dev/null +++ b/actionpack/test/fixtures/translations/templates/found.erb @@ -0,0 +1 @@ +<%= t('.foo') %> diff --git a/actionpack/test/fixtures/translations/templates/missing.erb b/actionpack/test/fixtures/translations/templates/missing.erb new file mode 100644 index 0000000000..0f3f17f8ef --- /dev/null +++ b/actionpack/test/fixtures/translations/templates/missing.erb @@ -0,0 +1 @@ +<%= t('.missing') %> diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb index 763080550b..67d459136b 100644 --- a/actionpack/test/template/translation_helper_test.rb +++ b/actionpack/test/template/translation_helper_test.rb @@ -4,60 +4,73 @@ class TranslationHelperTest < ActiveSupport::TestCase include ActionView::Helpers::TagHelper include ActionView::Helpers::TranslationHelper - attr_reader :request + attr_reader :request, :view + def setup + I18n.backend.store_translations(:en, + :translations => { + :templates => { + :found => { :foo => 'Foo' }, + :array => { :foo => { :bar => 'Foo Bar' } } + }, + :foo => 'Foo', + :hello => 'Hello World', + :html => 'Hello World', + :hello_html => 'Hello World', + :array_html => %w(foo bar), + :array => %w(foo bar) + } + ) + @view = ::ActionView::Base.new(ActionController::Base.view_paths, {}) end - def test_delegates_to_i18n_setting_the_raise_option - I18n.expects(:translate).with(:foo, :locale => 'en', :raise => true).returns("") + def test_delegates_to_i18n_setting_the_rescue_format_option_to_html + I18n.expects(:translate).with(:foo, :locale => 'en', :rescue_format => :html).returns("") translate :foo, :locale => 'en' end + def test_delegates_localize_to_i18n + @time = Time.utc(2008, 7, 8, 12, 18, 38) + I18n.expects(:localize).with(@time) + localize @time + end + def test_returns_missing_translation_message_wrapped_into_span - expected = 'en, foo' - assert_equal expected, translate(:foo) + expected = 'Missing' + assert_equal expected, translate(:"translations.missing") end def test_translation_returning_an_array - I18n.expects(:translate).with(:foo, :raise => true).returns(["foo", "bar"]) - assert_equal ["foo", "bar"], translate(:foo) + expected = %w(foo bar) + assert_equal expected, translate(:"translations.array") end - def test_delegates_localize_to_i18n - @time = Time.utc(2008, 7, 8, 12, 18, 38) - I18n.expects(:localize).with(@time) - localize @time + def test_finds_translation_scoped_by_partial + assert_equal 'Foo', view.render(:file => 'translations/templates/found').strip end - def test_scoping_by_partial - I18n.expects(:translate).with("test.translation.helper", :raise => true).returns("helper") - @view = ::ActionView::Base.new(ActionController::Base.view_paths, {}) - assert_equal "helper", @view.render(:file => "test/translation") + def test_finds_array_of_translations_scoped_by_partial + assert_equal 'Foo Bar', @view.render(:file => 'translations/templates/array').strip end - def test_scoping_by_partial_of_an_array - I18n.expects(:translate).with("test.scoped_translation.foo.bar", :raise => true).returns(["foo", "bar"]) - @view = ::ActionView::Base.new(ActionController::Base.view_paths, {}) - assert_equal "foobar", @view.render(:file => "test/scoped_translation") + def test_missing_translation_scoped_by_partial + expected = 'Missing' + assert_equal expected, view.render(:file => 'translations/templates/missing').strip end def test_translate_does_not_mark_plain_text_as_safe_html - I18n.expects(:translate).with("hello", :raise => true).returns("Hello World") - assert_equal false, translate("hello").html_safe? + assert_equal false, translate(:'translations.hello').html_safe? end def test_translate_marks_translations_named_html_as_safe_html - I18n.expects(:translate).with("html", :raise => true).returns("Hello World") - assert translate("html").html_safe? + assert translate(:'translations.html').html_safe? end def test_translate_marks_translations_with_a_html_suffix_as_safe_html - I18n.expects(:translate).with("hello_html", :raise => true).returns("Hello World") - assert translate("hello_html").html_safe? + assert translate(:'translations.hello_html').html_safe? end def test_translation_returning_an_array_ignores_html_suffix - I18n.expects(:translate).with(:foo_html, :raise => true).returns(["foo", "bar"]) - assert_equal ["foo", "bar"], translate(:foo_html) + assert_equal ["foo", "bar"], translate(:'translations.array_html') end end -- cgit v1.2.3 From be4551f63bc3dec7e182371d25e7b9ee0e9148c4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 4 Dec 2010 19:01:00 -0200 Subject: Use ||= here --- actionpack/lib/action_view/helpers/translation_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index e7ec1df2c8..76dac20f4b 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -44,7 +44,7 @@ module ActionView # naming convention helps to identify translations that include HTML tags so that # you know what kind of output to expect when you call translate in a template. def translate(key, options = {}) - options.merge!(:rescue_format => :html) unless options.key?(:rescue_format) + options[:rescue_format] ||= :html translation = I18n.translate(scope_key_by_partial(key), options) if html_safe_translation_key?(key) && translation.respond_to?(:html_safe) translation.html_safe -- cgit v1.2.3 From b696dd70db651c6cb4a096dd0d5762416acd9917 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 4 Dec 2010 20:07:54 -0200 Subject: Allow back passing :rescue_format => nil and test added --- actionpack/lib/action_view/helpers/translation_helper.rb | 2 +- actionpack/test/template/translation_helper_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index 76dac20f4b..e7ec1df2c8 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -44,7 +44,7 @@ module ActionView # naming convention helps to identify translations that include HTML tags so that # you know what kind of output to expect when you call translate in a template. def translate(key, options = {}) - options[:rescue_format] ||= :html + options.merge!(:rescue_format => :html) unless options.key?(:rescue_format) translation = I18n.translate(scope_key_by_partial(key), options) if html_safe_translation_key?(key) && translation.respond_to?(:html_safe) translation.html_safe diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb index 67d459136b..9b5c6d127c 100644 --- a/actionpack/test/template/translation_helper_test.rb +++ b/actionpack/test/template/translation_helper_test.rb @@ -40,6 +40,11 @@ class TranslationHelperTest < ActiveSupport::TestCase assert_equal expected, translate(:"translations.missing") end + def test_returns_missing_translation_message_using_nil_as_rescue_format + expected = 'translation missing: en.translations.missing' + assert_equal expected, translate(:"translations.missing", :rescue_format => nil) + end + def test_translation_returning_an_array expected = %w(foo bar) assert_equal expected, translate(:"translations.array") -- cgit v1.2.3 From e1d0d5ae81d2b02eebb1afbfb79edf0a2da2d48e Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Sat, 4 Dec 2010 22:40:05 -0200 Subject: Fix mime type doc typos --- actionpack/lib/action_dispatch/http/mime_type.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 08eab5634a..c85aa64572 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -173,10 +173,10 @@ module Mime end # input: 'text' - # returend value: [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] + # returned value: [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] # # input: 'application' - # returend value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM + # returned value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM] def parse_data_with_trailing_star(input) keys = Mime::LOOKUP.keys.select{|k| k.include?(input)} Mime::LOOKUP.values_at(*keys).uniq -- cgit v1.2.3 From 3ac844deec6070f35634acca0ae9007280b13e5d Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 6 Dec 2010 16:38:47 -0500 Subject: Add to documentation that action caching does handle HTTP_ACCEPT attribute properly and might provide wrong result. Use params[:format] to avoid this issue. --- actionpack/lib/action_controller/caching/actions.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index d69d96b974..cb79e51dbf 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -71,6 +71,11 @@ module ActionController #:nodoc: # If you pass :layout => false, it will only cache your action # content. It is useful when your layout has dynamic information. # + # Note: If action caching is being performed for different MIME types + # and those MIME types are being determined by HTTP_ACCEPT header atttribute + # and noth using params[:format] then both the cached data and the content-type + # of the response could be wrong. The safest way to use action caching is to + # pass non-html attribute as params[:format] . module Actions extend ActiveSupport::Concern -- cgit v1.2.3 From 0aa78826e4857dbaaaf8a0779848d11ab6e0ad5d Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 8 Dec 2010 21:20:53 +0100 Subject: makes a pass to the action caching rdoc --- .../lib/action_controller/caching/actions.rb | 73 ++++++++++++---------- 1 file changed, 41 insertions(+), 32 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index cb79e51dbf..a4bac3caed 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -4,25 +4,26 @@ module ActionController #:nodoc: module Caching # Action caching is similar to page caching by the fact that the entire # output of the response is cached, but unlike page caching, every - # request still goes through the Action Pack. The key benefit - # of this is that filters are run before the cache is served, which - # allows for authentication and other restrictions on whether someone - # is allowed to see the cache. Example: + # request still goes through Action Pack. The key benefit of this is + # that filters run before the cache is served, which allows for + # authentication and other restrictions on whether someone is allowed + # to execute such action. Example: # # class ListsController < ApplicationController # before_filter :authenticate, :except => :public + # # caches_page :public - # caches_action :index, :show, :feed + # caches_action :index, :show # end # - # In this example, the public action doesn't require authentication, - # so it's possible to use the faster page caching method. But both - # the show and feed action are to be shielded behind the authenticate - # filter, so we need to implement those as action caches. + # In this example, the +public+ action doesn't require authentication + # so it's possible to use the faster page caching. On the other hand + # +index+ and +show+ require authentication. They can still be cached, + # but we need action caching for them. # - # Action caching internally uses the fragment caching and an around - # filter to do the job. The fragment cache is named according to both - # the current host and the path. So a page that is accessed at + # Action caching uses fragment caching internally and an around + # filter to do the job. The fragment cache is named according to + # the host and path of the request. A page that is accessed at # http://david.example.com/lists/show/1 will result in a fragment named # david.example.com/lists/show/1. This allows the cacher to # differentiate between david.example.com/lists/ and @@ -38,19 +39,23 @@ module ActionController #:nodoc: # :action => 'list', :format => :xml. # # You can set modify the default action cache path by passing a - # :cache_path option. This will be passed directly to - # ActionCachePath.path_for. This is handy for actions with multiple - # possible routes that should be cached differently. If a block is - # given, it is called with the current controller instance. + # :cache_path option. This will be passed directly to + # ActionCachePath.path_for. This is handy for actions with + # multiple possible routes that should be cached differently. If a + # block is given, it is called with the current controller instance. + # + # And you can also use :if (or :unless) to pass a + # proc that specifies when the action should be cached. # - # And you can also use :if (or :unless) to pass a Proc that - # specifies when the action should be cached. + # Finally, if you are using memcached, you can also pass :expires_in. # - # Finally, if you are using memcached, you can also pass :expires_in. + # The following example depicts some of the points made above: # # class ListsController < ApplicationController # before_filter :authenticate, :except => :public - # caches_page :public + # + # caches_page :public + # # caches_action :index, :if => proc do |c| # !c.request.format.json? # cache if is not a JSON request # end @@ -58,24 +63,28 @@ module ActionController #:nodoc: # caches_action :show, :cache_path => { :project => 1 }, # :expires_in => 1.hour # - # caches_action :feed, :cache_path => proc do |controller| - # if controller.params[:user_id] - # controller.send(:user_list_url, - # controller.params[:user_id], controller.params[:id]) + # caches_action :feed, :cache_path => proc do |c| + # if c.params[:user_id] + # c.send(:user_list_url, + # c.params[:user_id], c.params[:id]) # else - # controller.send(:list_url, controller.params[:id]) + # c.send(:list_url, c.params[:id]) # end # end # end # - # If you pass :layout => false, it will only cache your action - # content. It is useful when your layout has dynamic information. + # If you pass :layout => false, it will only cache your action + # content. That's useful when your layout has dynamic information. + # + # Warning: If the format of the request is determined by the Accept HTTP + # header the Content-Type of the cached response could be wrong because + # no information about the MIME type is stored in the cache key. So, if + # you first ask for MIME type M in the Accept header, a cache entry is + # created, and then perform a second resquest to the same resource asking + # for a different MIME type, you'd get the content cached for M. # - # Note: If action caching is being performed for different MIME types - # and those MIME types are being determined by HTTP_ACCEPT header atttribute - # and noth using params[:format] then both the cached data and the content-type - # of the response could be wrong. The safest way to use action caching is to - # pass non-html attribute as params[:format] . + # The :format parameter is taken into account though. The safest + # way to cache by MIME type is to pass the format in the route. module Actions extend ActiveSupport::Concern -- cgit v1.2.3 From a47f31c59399204947dacb2b54fccc6987b137ee Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Thu, 9 Dec 2010 20:01:42 +1000 Subject: mapper.rb: add "options" to make the default-to-namespace-name line read better --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 5a38158e9f..11ac8fed20 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -563,7 +563,7 @@ module ActionDispatch # admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"} # === Supported options # - # The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+ all default to the name of the namespace. + # The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+ options all default to the name of the namespace. # # [:path] # The path prefix for the routes. -- cgit v1.2.3 From d2f98e5b556815f7b9cf84d3702d93a0bfb7d433 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Thu, 9 Dec 2010 20:03:14 +1000 Subject: indent code samples for mount doc --- actionpack/lib/action_dispatch/routing/mapper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 11ac8fed20..086366c740 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -269,18 +269,18 @@ module ActionDispatch # Mount a Rack-based application to be used within the application. # - # mount SomeRackApp, :at => "some_route" + # mount SomeRackApp, :at => "some_route" # # Alternatively: # - # mount(SomeRackApp => "some_route") + # mount(SomeRackApp => "some_route") # # All mounted applications come with routing helpers to access them. # These are named after the class specified, so for the above example # the helper is either +some_rack_app_path+ or +some_rack_app_url+. # To customize this helper's name, use the +:as+ option: # - # mount(SomeRackApp => "some_route", :as => "exciting") + # mount(SomeRackApp => "some_route", :as => "exciting") # # This will generate the +exciting_path+ and +exciting_url+ helpers # which can be used to navigate to this mounted app. -- cgit v1.2.3 From fe0e3880e8ce8311882f3856b689c2f79a13ced4 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Thu, 9 Dec 2010 20:21:08 +1000 Subject: root route should go at the *top* of the routes file, because it is the most popular route and should be matched first --- actionpack/lib/action_dispatch/routing/mapper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 086366c740..cf95f6fa53 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -247,7 +247,9 @@ module ActionDispatch # # root :to => 'pages#main' # - # You should put the root route at the end of config/routes.rb. + # You should put the root route at the top of config/routes.rb, + # because this means it will be matched first. As this is the most popular route + # of most Rails applications, this is beneficial. def root(options = {}) match '/', options.reverse_merge(:as => :root) end -- cgit v1.2.3 From 28cf77203b0b5af648e441b5d9cfb75863ba2f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 9 Dec 2010 13:15:25 +0100 Subject: Check if the routes object really responds to define_mount_prefix. --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 +- actionpack/test/dispatch/mount_test.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 5a38158e9f..47de5848fa 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -327,7 +327,7 @@ module ActionDispatch end def define_generate_prefix(app, name) - return unless app.respond_to?(:routes) + return unless app.respond_to?(:routes) && app.routes.respond_to?(:define_mounted_helper) _route = @set.named_routes.routes[name.to_sym] _routes = @set diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb index 0f584af31e..1a032539b9 100644 --- a/actionpack/test/dispatch/mount_test.rb +++ b/actionpack/test/dispatch/mount_test.rb @@ -2,6 +2,17 @@ require 'abstract_unit' class TestRoutingMount < ActionDispatch::IntegrationTest Router = ActionDispatch::Routing::RouteSet.new + + class FakeEngine + def self.routes + Object.new + end + + def self.call(env) + [200, {"Content-Type" => "text/html"}, ["OK"]] + end + end + Router.draw do SprocketsApp = lambda { |env| [200, {"Content-Type" => "text/html"}, ["#{env["SCRIPT_NAME"]} -- #{env["PATH_INFO"]}"]] @@ -10,6 +21,8 @@ class TestRoutingMount < ActionDispatch::IntegrationTest mount SprocketsApp, :at => "/sprockets" mount SprocketsApp => "/shorthand" + mount FakeEngine, :at => "/fakeengine" + scope "/its_a" do mount SprocketsApp, :at => "/sprocket" end @@ -33,4 +46,9 @@ class TestRoutingMount < ActionDispatch::IntegrationTest get "/shorthand/omg" assert_equal "/shorthand -- /omg", response.body end + + def test_with_fake_engine_does_not_call_invalid_method + get "/fakeengine" + assert_equal "OK", response.body + end end \ No newline at end of file -- cgit v1.2.3 From cc70ac9508dff6a4406f446d7a53d05f6c7d9f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 9 Dec 2010 13:15:40 +0100 Subject: Properly check the arity for template handlers. --- actionpack/lib/action_view/template.rb | 2 +- actionpack/test/template/render_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 831a19654e..0d8373ef14 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -275,7 +275,7 @@ module ActionView end arity = @handler.respond_to?(:arity) ? @handler.arity : @handler.method(:call).arity - code = arity == 1 ? @handler.call(self) : @handler.call(self, view) + code = arity.abs == 1 ? @handler.call(self) : @handler.call(self, view) # Make sure that the resulting String to be evalled is in the # encoding of the code diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 8087429d62..38bedd2e4e 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -225,6 +225,11 @@ module RenderTestCases %'"#{template.class} #{view.class}"' end + def test_render_inline_with_render_from_to_proc + ActionView::Template.register_template_handler :ruby_handler, :source.to_proc + assert_equal '3', @view.render(:inline => "(1 + 2).to_s", :type => :ruby_handler) + end + def test_render_inline_with_template_handler_with_view ActionView::Template.register_template_handler :with_view, WithViewHandler assert_equal 'ActionView::Template ActionView::Base', @view.render(:inline => "Hello, World!", :type => :with_view) -- cgit v1.2.3 From 8e6d27641cf213a13d51491cecfbfa1d3c8822fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 9 Dec 2010 13:40:45 +0100 Subject: Clean up asset_host and asset_path. --- actionpack/lib/action_controller/railtie.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index c5a661f2b0..f0c29825ba 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -27,8 +27,8 @@ module ActionController options.page_cache_directory ||= paths["public"].first # make sure readers methods get compiled - options.asset_path ||= nil - options.asset_host ||= nil + options.asset_path ||= app.config.asset_path + options.asset_host ||= app.config.asset_host ActiveSupport.on_load(:action_controller) do include app.routes.mounted_helpers -- cgit v1.2.3 From d3f7e565d1a6ee15605971c3f3fea6e756a1ff99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 9 Dec 2010 14:06:44 +0100 Subject: Ensure resolvers backward compatibility. --- actionpack/lib/action_view/lookup_context.rb | 2 +- actionpack/lib/action_view/path_set.rb | 6 ++---- actionpack/lib/action_view/template/resolver.rb | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 27f94a73a6..d524c68450 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -109,7 +109,7 @@ module ActionView def args_for_lookup(name, prefix, partial, keys) #:nodoc: name, prefix = normalize_name(name, prefix) - [name, prefix, partial || false, @details, keys, details_key] + [name, prefix, partial || false, @details, details_key, keys] end # Support legacy foo.erb names even though we now ignore .erb diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index dc26d75ff3..fa35120a0d 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -10,10 +10,8 @@ module ActionView #:nodoc: METHOD end - def find(path, prefix = nil, partial = false, details = {}, keys = [], key = nil) - template = find_all(path, prefix, partial, details, keys, key).first - raise MissingTemplate.new(self, "#{prefix}/#{path}", details, partial) unless template - template + def find(*args) + find_all(*args).first || raise(MissingTemplate.new(self, "#{args[1]}/#{args[0]}", args[3], args[2])) end def find_all(*args) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 9f15661669..a17454da28 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -15,7 +15,7 @@ module ActionView end # Normalizes the arguments and passes it on to find_template. - def find_all(name, prefix=nil, partial=false, details={}, locals=[], key=nil) + def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[]) cached(key, [name, prefix, partial], details, locals) do find_templates(name, prefix, partial, details) end -- cgit v1.2.3 From 0027b654215cd6310d0d17daeaafec8ebbfb38d4 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Sat, 4 Dec 2010 17:40:54 -0500 Subject: Ensure that while caching a page rails takes into account the resolved mime type for the request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#6110 state:resolved] Signed-off-by: José Valim --- actionpack/lib/action_controller/caching/pages.rb | 20 +++++++++++++------- actionpack/test/controller/caching_test.rb | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb index 104157d0b1..3e57d2c236 100644 --- a/actionpack/lib/action_controller/caching/pages.rb +++ b/actionpack/lib/action_controller/caching/pages.rb @@ -70,9 +70,9 @@ module ActionController #:nodoc: # Manually cache the +content+ in the key determined by +path+. Example: # cache_page "I'm the cached content", "/lists/show" - def cache_page(content, path) + def cache_page(content, path, extension = nil) return unless perform_caching - path = page_cache_path(path) + path = page_cache_path(path, extension) instrument_page_cache :write_page, path do FileUtils.makedirs(File.dirname(path)) @@ -97,14 +97,16 @@ module ActionController #:nodoc: end private - def page_cache_file(path) + def page_cache_file(path, extension) name = (path.empty? || path == "/") ? "/index" : URI.parser.unescape(path.chomp('/')) - name << page_cache_extension unless (name.split('/').last || name).include? '.' + unless (name.split('/').last || name).include? '.' + name << (extension || self.page_cache_extension) + end return name end - def page_cache_path(path) - page_cache_directory + page_cache_file(path) + def page_cache_path(path, extension = nil) + page_cache_directory + page_cache_file(path, extension) end def instrument_page_cache(name, path) @@ -145,7 +147,11 @@ module ActionController #:nodoc: request.path end - self.class.cache_page(content || response.body, path) + if (type = Mime::LOOKUP[self.content_type]) && (type_symbol = type.symbol).present? + extension = ".#{type_symbol}" + end + + self.class.cache_page(content || response.body, path, extension) end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 914ae56032..c7b54eb0ba 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -16,6 +16,7 @@ end class PageCachingTestController < CachingController caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? } caches_page :found, :not_found + caches_page :about_me def ok @@ -47,6 +48,14 @@ class PageCachingTestController < CachingController def trailing_slash render :text => "Sneak attack" end + + def about_me + respond_to do |format| + format.html {render :text => 'I am html'} + format.xml {render :text => 'I am xml'} + end + end + end class PageCachingTest < ActionController::TestCase @@ -111,6 +120,13 @@ class PageCachingTest < ActionController::TestCase assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html") end + def test_should_obey_http_accept_attribute + @request.env['HTTP_ACCEPT'] = 'text/xml' + get :about_me + assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/about_me.xml") + assert_equal 'I am xml', @response.body + end + def test_should_cache_with_trailing_slash_on_url @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash/' assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html") -- cgit v1.2.3 From f0d4b7f2a655ca2fb435af798714fee2de232d1e Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 10 Dec 2010 09:34:40 +1000 Subject: root method options are the same as the match method --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index cf95f6fa53..3039f88f71 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -247,6 +247,8 @@ module ActionDispatch # # root :to => 'pages#main' # + # For options, see the +match+ method's documentation, as +root+ uses it internally. + # # You should put the root route at the top of config/routes.rb, # because this means it will be matched first. As this is the most popular route # of most Rails applications, this is beneficial. -- cgit v1.2.3 From dbf955c03b8d185b7977d90281389cf52d546c5d Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 10 Dec 2010 15:55:46 +1000 Subject: Action Controller Overview: Remove dead link to the API docs for filters --- actionpack/lib/action_dispatch/routing/mapper.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 3039f88f71..494cdbf308 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1089,6 +1089,7 @@ module ActionDispatch end end + # See ActionDispatch::Routing::Mapper::Scoping#namespace def namespace(path, options = {}) if resource_scope? nested { super } -- cgit v1.2.3