mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
:subdomain, :domain and :tld_length options can now be used in url_for, allowing for easy manipulation of the host during link generation.
Signed-off-by: José Valim <jose.valim@gmail.com>
This commit is contained in:
committed by
José Valim
parent
9938a3fc78
commit
2fe43b694f
@@ -6,7 +6,8 @@ module ActionController
|
|||||||
|
|
||||||
def url_options
|
def url_options
|
||||||
@_url_options ||= super.reverse_merge(
|
@_url_options ||= super.reverse_merge(
|
||||||
:host => request.host_with_port,
|
:host => request.host,
|
||||||
|
:port => request.optional_port,
|
||||||
:protocol => request.protocol,
|
:protocol => request.protocol,
|
||||||
:_path_segments => request.symbolized_path_parameters
|
:_path_segments => request.symbolized_path_parameters
|
||||||
).freeze
|
).freeze
|
||||||
@@ -20,5 +21,6 @@ module ActionController
|
|||||||
@_url_options
|
@_url_options
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,27 @@ module ActionDispatch
|
|||||||
mattr_accessor :tld_length
|
mattr_accessor :tld_length
|
||||||
self.tld_length = 1
|
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
|
||||||
|
|
||||||
|
def self.named_host?(host)
|
||||||
|
!(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# Returns the complete URL used for this request.
|
# Returns the complete URL used for this request.
|
||||||
def url
|
def url
|
||||||
protocol + host_with_port + fullpath
|
protocol + host_with_port + fullpath
|
||||||
@@ -31,15 +52,18 @@ module ActionDispatch
|
|||||||
# Returns a \host:\port string for this request, such as "example.com" or
|
# Returns a \host:\port string for this request, such as "example.com" or
|
||||||
# "example.com:8080".
|
# "example.com:8080".
|
||||||
def host_with_port
|
def host_with_port
|
||||||
"#{host}#{port_string}"
|
opt_port = optional_port ? ":#{optional_port}" : nil
|
||||||
|
"#{host}#{opt_port}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the port number of this request as an integer.
|
# Returns the port number of this request as an integer.
|
||||||
def port
|
def port
|
||||||
if raw_host_with_port =~ /:(\d+)$/
|
@port ||= begin
|
||||||
$1.to_i
|
if raw_host_with_port =~ /:(\d+)$/
|
||||||
else
|
$1.to_i
|
||||||
standard_port
|
else
|
||||||
|
standard_port
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -56,10 +80,10 @@ module ActionDispatch
|
|||||||
port == standard_port
|
port == standard_port
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a \port suffix like ":8080" if the \port number of this request
|
# Returns a \port suffix like "8080" if the \port number of this request
|
||||||
# is not the default HTTP \port 80 or HTTPS \port 443.
|
# is not the default HTTP \port 80 or HTTPS \port 443.
|
||||||
def port_string
|
def optional_port
|
||||||
port == standard_port ? '' : ":#{port}"
|
standard_port? ? nil : port
|
||||||
end
|
end
|
||||||
|
|
||||||
def server_port
|
def server_port
|
||||||
@@ -69,9 +93,7 @@ module ActionDispatch
|
|||||||
# Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
|
# Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
|
||||||
# a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
|
# a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
|
||||||
def domain(tld_length = @@tld_length)
|
def domain(tld_length = @@tld_length)
|
||||||
return nil unless named_host?(host)
|
ActionDispatch::Http::URL.extract_domain(host, tld_length)
|
||||||
|
|
||||||
host.split('.').last(1 + tld_length).join('.')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
|
# Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
|
||||||
@@ -79,20 +101,17 @@ module ActionDispatch
|
|||||||
# such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
|
# such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
|
||||||
# in "www.rubyonrails.co.uk".
|
# in "www.rubyonrails.co.uk".
|
||||||
def subdomains(tld_length = @@tld_length)
|
def subdomains(tld_length = @@tld_length)
|
||||||
return [] unless named_host?(host)
|
ActionDispatch::Http::URL.extract_subdomains(host, tld_length)
|
||||||
parts = host.split('.')
|
|
||||||
parts[0..-(tld_length+2)]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns all the \subdomains as a string, so <tt>"dev.www"</tt> would be
|
||||||
|
# returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
|
||||||
|
# such as 2 to catch <tt>["www"]</tt> instead of <tt>"www.rubyonrails"</tt>
|
||||||
|
# in "www.rubyonrails.co.uk".
|
||||||
def subdomain(tld_length = @@tld_length)
|
def subdomain(tld_length = @@tld_length)
|
||||||
subdomains(tld_length).join('.')
|
subdomains(tld_length)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def named_host?(host)
|
|
||||||
!(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -485,7 +485,8 @@ module ActionDispatch
|
|||||||
Generator.new(options, recall, self, extras).generate
|
Generator.new(options, recall, self, extras).generate
|
||||||
end
|
end
|
||||||
|
|
||||||
RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash, :script_name]
|
RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
|
||||||
|
:trailing_slash, :script_name, :anchor, :params, :only_path ]
|
||||||
|
|
||||||
def _generate_prefix(options = {})
|
def _generate_prefix(options = {})
|
||||||
nil
|
nil
|
||||||
@@ -504,11 +505,8 @@ module ActionDispatch
|
|||||||
rewritten_url << (options[:protocol] || "http")
|
rewritten_url << (options[:protocol] || "http")
|
||||||
rewritten_url << "://" unless rewritten_url.match("://")
|
rewritten_url << "://" unless rewritten_url.match("://")
|
||||||
rewritten_url << rewrite_authentication(options)
|
rewritten_url << rewrite_authentication(options)
|
||||||
|
rewritten_url << host_from_options(options)
|
||||||
raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host]
|
rewritten_url << ":#{options.delete(:port)}" if options[:port]
|
||||||
|
|
||||||
rewritten_url << options[:host]
|
|
||||||
rewritten_url << ":#{options.delete(:port)}" if options.key?(:port)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
script_name = options.delete(:script_name)
|
script_name = options.delete(:script_name)
|
||||||
@@ -562,6 +560,34 @@ module ActionDispatch
|
|||||||
end
|
end
|
||||||
|
|
||||||
private
|
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]"
|
||||||
|
end
|
||||||
|
computed_host
|
||||||
|
end
|
||||||
|
|
||||||
|
def subdomain_and_domain(options)
|
||||||
|
tld_length = options[:tld_length] || ActionDispatch::Http::URL.tld_length
|
||||||
|
|
||||||
|
current_domain = ActionDispatch::Http::URL.extract_domain(options[:host], tld_length)
|
||||||
|
current_subdomain = ActionDispatch::Http::URL.extract_subdomain(options[:host], tld_length)
|
||||||
|
|
||||||
|
domain_parts = if options[:subdomain] && options[:domain]
|
||||||
|
[options[:subdomain], options[:domain]]
|
||||||
|
elsif options[:subdomain]
|
||||||
|
[options[:subdomain], current_domain]
|
||||||
|
elsif options[:domain]
|
||||||
|
[current_subdomain, options[:domain]]
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
domain_parts ? domain_parts.join('.') : nil
|
||||||
|
end
|
||||||
|
|
||||||
def handle_positional_args(options)
|
def handle_positional_args(options)
|
||||||
return unless args = options.delete(:_positional_args)
|
return unless args = options.delete(:_positional_args)
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ module ActionDispatch
|
|||||||
# * <tt>:host</tt> - Specifies the host the link should be targeted at.
|
# * <tt>:host</tt> - Specifies the host the link should be targeted at.
|
||||||
# If <tt>:only_path</tt> is false, this option must be
|
# If <tt>:only_path</tt> is false, this option must be
|
||||||
# provided either explicitly, or via +default_url_options+.
|
# provided either explicitly, or via +default_url_options+.
|
||||||
|
# * <tt>:subdomain</tt> - Specifies the subdomain of the link, using the +tld_length+
|
||||||
|
# to split the domain from the host.
|
||||||
|
# * <tt>:domain</tt> - Specifies the domain of the link, using the +tld_length+
|
||||||
|
# to split the subdomain from the host.
|
||||||
|
# * <tt>:tld_length</tt> - Optionally specify the tld length (only used if :subdomain
|
||||||
|
# or :domain are supplied).
|
||||||
# * <tt>:port</tt> - Optionally specify the port to connect to.
|
# * <tt>:port</tt> - Optionally specify the port to connect to.
|
||||||
# * <tt>:anchor</tt> - An anchor name to be appended to the path.
|
# * <tt>:anchor</tt> - An anchor name to be appended to the path.
|
||||||
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
|
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ module AbstractController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_exception_is_thrown_without_host
|
def test_exception_is_thrown_without_host
|
||||||
assert_raise RuntimeError do
|
assert_raise ArgumentError do
|
||||||
W.new.url_for :controller => 'c', :action => 'a', :id => 'i'
|
W.new.url_for :controller => 'c', :action => 'a', :id => 'i'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -60,6 +60,27 @@ module AbstractController
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_subdomain_may_be_changed
|
||||||
|
add_host!
|
||||||
|
assert_equal('http://api.basecamphq.com/c/a/i',
|
||||||
|
W.new.url_for(:subdomain => 'api', :controller => 'c', :action => 'a', :id => 'i')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_domain_may_be_changed
|
||||||
|
add_host!
|
||||||
|
assert_equal('http://www.37signals.com/c/a/i',
|
||||||
|
W.new.url_for(:domain => '37signals.com', :controller => 'c', :action => 'a', :id => 'i')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_tld_length_may_be_changed
|
||||||
|
add_host!
|
||||||
|
assert_equal('http://mobile.www.basecamphq.com/c/a/i',
|
||||||
|
W.new.url_for(:subdomain => 'mobile', :tld_length => 2, :controller => 'c', :action => 'a', :id => 'i')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def test_port
|
def test_port
|
||||||
add_host!
|
add_host!
|
||||||
assert_equal('http://www.basecamphq.com:3000/c/a/i',
|
assert_equal('http://www.basecamphq.com:3000/c/a/i',
|
||||||
|
|||||||
@@ -164,12 +164,12 @@ class RequestTest < ActiveSupport::TestCase
|
|||||||
assert !request.standard_port?
|
assert !request.standard_port?
|
||||||
end
|
end
|
||||||
|
|
||||||
test "port string" do
|
test "optional port" do
|
||||||
request = stub_request 'HTTP_HOST' => 'www.example.org:80'
|
request = stub_request 'HTTP_HOST' => 'www.example.org:80'
|
||||||
assert_equal "", request.port_string
|
assert_equal nil, request.optional_port
|
||||||
|
|
||||||
request = stub_request 'HTTP_HOST' => 'www.example.org:8080'
|
request = stub_request 'HTTP_HOST' => 'www.example.org:8080'
|
||||||
assert_equal ":8080", request.port_string
|
assert_equal 8080, request.optional_port
|
||||||
end
|
end
|
||||||
|
|
||||||
test "full path" do
|
test "full path" do
|
||||||
|
|||||||
Reference in New Issue
Block a user