mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Optimize path helpers.
This commit is contained in:
parent
fcef72890b
commit
d7014bc7ea
5 changed files with 81 additions and 29 deletions
|
@ -1,7 +1,7 @@
|
|||
# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
|
||||
# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
|
||||
# the <tt>_routes</tt> method. Otherwise, an exception will be raised.
|
||||
#
|
||||
# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
|
||||
# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
|
||||
# url options like the +host+. In order to do so, this module requires the host class
|
||||
# to implement +env+ and +request+, which need to be a Rack-compatible.
|
||||
#
|
||||
|
@ -18,7 +18,7 @@
|
|||
# @url = root_path # named route from the application.
|
||||
# end
|
||||
# end
|
||||
#
|
||||
#
|
||||
module ActionController
|
||||
module UrlFor
|
||||
extend ActiveSupport::Concern
|
||||
|
@ -26,22 +26,20 @@ module ActionController
|
|||
include AbstractController::UrlFor
|
||||
|
||||
def url_options
|
||||
@_url_options ||= super.reverse_merge(
|
||||
:host => request.host,
|
||||
:port => request.optional_port,
|
||||
:protocol => request.protocol,
|
||||
:_path_segments => request.symbolized_path_parameters
|
||||
).freeze
|
||||
@_url_options ||= begin
|
||||
hash = super.reverse_merge(
|
||||
:host => request.host,
|
||||
:port => request.optional_port,
|
||||
:protocol => request.protocol,
|
||||
:_path_segments => request.symbolized_path_parameters
|
||||
)
|
||||
|
||||
if _routes.equal?(env["action_dispatch.routes"])
|
||||
@_url_options.dup.tap do |options|
|
||||
options[:script_name] = request.script_name.dup
|
||||
options.freeze
|
||||
if _routes.equal?(env["action_dispatch.routes"])
|
||||
hash[:script_name] = request.script_name.dup
|
||||
end
|
||||
else
|
||||
@_url_options
|
||||
|
||||
hash.freeze
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,7 +40,9 @@ module ActionDispatch
|
|||
rewritten_url << ":#{options.delete(:port)}" if options[:port]
|
||||
end
|
||||
|
||||
path = options.delete(:path) || ''
|
||||
path = ""
|
||||
path << options.delete(:script_name).to_s.chomp("/")
|
||||
path << options.delete(:path).to_s
|
||||
|
||||
params = options[:params] || {}
|
||||
params.reject! {|k,v| v.to_param.nil? }
|
||||
|
|
|
@ -446,7 +446,11 @@ module ActionDispatch
|
|||
_route = @set.named_routes.routes[name.to_sym]
|
||||
_routes = @set
|
||||
app.routes.define_mounted_helper(name)
|
||||
app.routes.class_eval do
|
||||
app.routes.singleton_class.class_eval do
|
||||
define_method :mounted? do
|
||||
true
|
||||
end
|
||||
|
||||
define_method :_generate_prefix do |options|
|
||||
prefix_options = options.slice(*_route.segment_keys)
|
||||
# we must actually delete prefix segment keys to avoid passing them to next url_for
|
||||
|
|
|
@ -191,14 +191,55 @@ module ActionDispatch
|
|||
selector = url_helper_name(name, kind)
|
||||
hash_access_method = hash_access_name(name, kind)
|
||||
|
||||
@module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
|
||||
remove_possible_method :#{selector}
|
||||
def #{selector}(*args)
|
||||
url_for(#{hash_access_method}(*args))
|
||||
end
|
||||
END_EVAL
|
||||
if optimize_helper?(kind, route)
|
||||
@module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
|
||||
remove_possible_method :#{selector}
|
||||
def #{selector}(*args)
|
||||
if args.size == #{route.required_parts.size} && !args.last.is_a?(Hash) && _optimized_routes?
|
||||
options = #{options.inspect}.merge!(url_options)
|
||||
options[:path] = "#{optimized_helper(route)}"
|
||||
ActionDispatch::Http::URL.url_for(options)
|
||||
else
|
||||
url_for(#{hash_access_method}(*args))
|
||||
end
|
||||
end
|
||||
END_EVAL
|
||||
else
|
||||
@module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
|
||||
remove_possible_method :#{selector}
|
||||
def #{selector}(*args)
|
||||
url_for(#{hash_access_method}(*args))
|
||||
end
|
||||
END_EVAL
|
||||
end
|
||||
|
||||
helpers << selector
|
||||
end
|
||||
|
||||
# If we are generating a path helper and we don't have a *path segment.
|
||||
# We can optimize the routes generation to a string interpolation if
|
||||
# it meets the appropriated runtime conditions.
|
||||
#
|
||||
# TODO We are enabling this only for path helpers, remove the
|
||||
# kind == :path and fix the failures to enable it for url as well.
|
||||
def optimize_helper?(kind, route) #:nodoc:
|
||||
kind == :path && route.ast.grep(Journey::Nodes::Star).empty?
|
||||
end
|
||||
|
||||
# Generates the interpolation to be used in the optimized helper.
|
||||
def optimized_helper(route)
|
||||
string_route = route.ast.to_s
|
||||
|
||||
while string_route.gsub!(/\([^\)]*\)/, "")
|
||||
true
|
||||
end
|
||||
|
||||
route.required_parts.each_with_index do |part, i|
|
||||
string_route.gsub!(part.inspect, "\#{Journey::Router::Utils.escape_fragment(args[#{i}].to_param)}")
|
||||
end
|
||||
|
||||
string_route
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
|
||||
|
@ -557,6 +598,10 @@ module ActionDispatch
|
|||
RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
|
||||
:trailing_slash, :anchor, :params, :only_path, :script_name]
|
||||
|
||||
def mounted?
|
||||
false
|
||||
end
|
||||
|
||||
def _generate_prefix(options = {})
|
||||
nil
|
||||
end
|
||||
|
@ -568,19 +613,17 @@ module ActionDispatch
|
|||
|
||||
user, password = extract_authentication(options)
|
||||
path_segments = options.delete(:_path_segments)
|
||||
script_name = options.delete(:script_name)
|
||||
|
||||
path = (script_name.blank? ? _generate_prefix(options) : script_name.chomp('/')).to_s
|
||||
script_name = options.delete(:script_name).presence || _generate_prefix(options)
|
||||
|
||||
path_options = options.except(*RESERVED_OPTIONS)
|
||||
path_options = yield(path_options) if block_given?
|
||||
|
||||
path_addition, params = generate(path_options, path_segments || {})
|
||||
path << path_addition
|
||||
path, params = generate(path_options, path_segments || {})
|
||||
params.merge!(options[:params] || {})
|
||||
|
||||
ActionDispatch::Http::URL.url_for(options.merge!({
|
||||
:path => path,
|
||||
:script_name => script_name,
|
||||
:params => params,
|
||||
:user => user,
|
||||
:password => password
|
||||
|
|
|
@ -152,6 +152,11 @@ module ActionDispatch
|
|||
|
||||
protected
|
||||
|
||||
def _optimized_routes?
|
||||
return @_optimized_routes if defined?(@_optimized_routes)
|
||||
@_optimized_routes = default_url_options.empty? && !_routes.mounted? && _routes.default_url_options.empty?
|
||||
end
|
||||
|
||||
def _with_routes(routes)
|
||||
old_routes, @_routes = @_routes, routes
|
||||
yield
|
||||
|
|
Loading…
Reference in a new issue