提交 9b4514c3 编写于 作者: A Andrew White

Copy literal route constraints to defaults - fixes #3571 and #6224.

上级 0d48b12f
## Rails 4.0.0 (unreleased) ## ## Rails 4.0.0 (unreleased) ##
* Copy literal route constraints to defaults so that url generation know about them.
The copied constraints are `:protocol`, `:subdomain`, `:domain`, `:host` and `:port`.
*Andrew White*
* `respond_to` and `respond_with` now raise ActionController::UnknownFormat instead * `respond_to` and `respond_with` now raise ActionController::UnknownFormat instead
of directly returning head 406. The exception is rescued and converted to 406 of directly returning head 406. The exception is rescued and converted to 406
in the exception handling middleware. *Steven Soroka* in the exception handling middleware. *Steven Soroka*
......
require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/reverse_merge' require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/enumerable' require 'active_support/core_ext/enumerable'
require 'active_support/inflector' require 'active_support/inflector'
...@@ -100,6 +101,10 @@ def normalize_options! ...@@ -100,6 +101,10 @@ def normalize_options!
raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}" raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
end end
end end
if @options[:constraints].is_a?(Hash)
(@options[:defaults] ||= {}).reverse_merge!(defaults_from_constraints(@options[:constraints]))
end
end end
# match "account/overview" # match "account/overview"
...@@ -245,6 +250,11 @@ def default_controller ...@@ -245,6 +250,11 @@ def default_controller
def default_action def default_action
@options[:action] || @scope[:action] @options[:action] || @scope[:action]
end end
def defaults_from_constraints(constraints)
url_keys = [:protocol, :subdomain, :domain, :host, :port]
constraints.slice(*url_keys).select{ |k, v| v.is_a?(String) || v.is_a?(Fixnum) }
end
end end
# Invokes Rack::Mount::Utils.normalize path and ensure that # Invokes Rack::Mount::Utils.normalize path and ensure that
...@@ -641,6 +651,10 @@ def scope(*args) ...@@ -641,6 +651,10 @@ def scope(*args)
block, options[:constraints] = options[:constraints], {} block, options[:constraints] = options[:constraints], {}
end end
if options[:constraints].is_a?(Hash)
(options[:defaults] ||= {}).reverse_merge!(defaults_from_constraints(options[:constraints]))
end
scope_options.each do |option| scope_options.each do |option|
if value = options.delete(option) if value = options.delete(option)
recover[option] = @scope[option] recover[option] = @scope[option]
...@@ -849,6 +863,11 @@ def merge_shallow_scope(parent, child) #:nodoc: ...@@ -849,6 +863,11 @@ def merge_shallow_scope(parent, child) #:nodoc:
def override_keys(child) #:nodoc: def override_keys(child) #:nodoc:
child.key?(:only) || child.key?(:except) ? [:only, :except] : [] child.key?(:only) || child.key?(:except) ? [:only, :except] : []
end end
def defaults_from_constraints(constraints)
url_keys = [:protocol, :subdomain, :domain, :host, :port]
constraints.slice(*url_keys).select{ |k, v| v.is_a?(String) || v.is_a?(Fixnum) }
end
end end
# Resource routing allows you to quickly declare all of the common routes # Resource routing allows you to quickly declare all of the common routes
......
...@@ -47,7 +47,7 @@ def test_assert_recognizes ...@@ -47,7 +47,7 @@ def test_assert_recognizes
def test_assert_recognizes_with_extras def test_assert_recognizes_with_extras
assert_recognizes({ :controller => 'articles', :action => 'index', :page => '1' }, '/articles', { :page => '1' }) assert_recognizes({ :controller => 'articles', :action => 'index', :page => '1' }, '/articles', { :page => '1' })
end end
def test_assert_recognizes_with_method def test_assert_recognizes_with_method
assert_recognizes({ :controller => 'articles', :action => 'create' }, { :path => '/articles', :method => :post }) assert_recognizes({ :controller => 'articles', :action => 'create' }, { :path => '/articles', :method => :post })
assert_recognizes({ :controller => 'articles', :action => 'update', :id => '1' }, { :path => '/articles/1', :method => :put }) assert_recognizes({ :controller => 'articles', :action => 'update', :id => '1' }, { :path => '/articles/1', :method => :put })
...@@ -57,7 +57,7 @@ def test_assert_recognizes_with_hash_constraint ...@@ -57,7 +57,7 @@ def test_assert_recognizes_with_hash_constraint
assert_raise(ActionController::RoutingError) do assert_raise(ActionController::RoutingError) do
assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'http://test.host/secure/articles') assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'http://test.host/secure/articles')
end end
assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'https://test.host/secure/articles') assert_recognizes({ :controller => 'secure_articles', :action => 'index', :protocol => 'https://' }, 'https://test.host/secure/articles')
end end
def test_assert_recognizes_with_block_constraint def test_assert_recognizes_with_block_constraint
...@@ -90,7 +90,7 @@ def test_assert_routing_with_hash_constraint ...@@ -90,7 +90,7 @@ def test_assert_routing_with_hash_constraint
assert_raise(ActionController::RoutingError) do assert_raise(ActionController::RoutingError) do
assert_routing('http://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' }) assert_routing('http://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' })
end end
assert_routing('https://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' }) assert_routing('https://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index', :protocol => 'https://' })
end end
def test_assert_routing_with_block_constraint def test_assert_routing_with_block_constraint
......
...@@ -2606,3 +2606,45 @@ def app; Routes end ...@@ -2606,3 +2606,45 @@ def app; Routes end
assert_raises(ActionController::RoutingError) { product_path(nil) } assert_raises(ActionController::RoutingError) { product_path(nil) }
end end
end end
class TestUrlConstraints < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
app.draw do
ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
constraints :subdomain => 'admin' do
get '/' => ok, :as => :admin_root
end
scope :constraints => { :protocol => 'https://' } do
get '/' => ok, :as => :secure_root
end
get '/' => ok, :as => :alternate_root, :constraints => { :port => 8080 }
end
end
include Routes.url_helpers
def app; Routes end
test "constraints are copied to defaults when using constraints method" do
assert_equal 'http://admin.example.com/', admin_root_url
get 'http://admin.example.com/'
assert_response :success
end
test "constraints are copied to defaults when using scope constraints hash" do
assert_equal 'https://www.example.com/', secure_root_url
get 'https://www.example.com/'
assert_response :success
end
test "constraints are copied to defaults when using route constraints hash" do
assert_equal 'http://www.example.com:8080/', alternate_root_url
get 'http://www.example.com:8080/'
assert_response :success
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册