リファレンス読んでもいまいちわからなかったので、そういうときはRailsそのもののソースを読むに限る。
_path
でgrepしてみると、
# actionpack/lib/action_dispatch/routing/route_set.rb
def add(name, route)
key = name.to_sym
path_name = :"#{name}_path"
url_name = :"#{name}_url"
if routes.key? key
@path_helpers_module.send :undef_method, path_name
@url_helpers_module.send :undef_method, url_name
end
routes[key] = route
define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
define_url_helper @url_helpers_module, route, url_name, route.defaults, name, UNKNOWN
@path_helpers << path_name
@url_helpers << url_name
end
bundle exec rake routes
したときに出てくるルート情報っぽいものを作ってる場所なんだけど、そこで
define_url_helper
ってのがあった。きっとこれだ。
# actionpack/lib/action_dispatch/routing/route_set.rb
# Create a URL helper allowing ordered parameters to be associated
# with corresponding dynamic segments, so you can do:
#
# foo_url(bar, baz, bang)
#
# Instead of:
#
# foo_url(bar: bar, baz: baz, bang: bang)
#
# Also allow options hash, so you can do:
#
# foo_url(bar, baz, bang, sort_by: 'baz')
#
def define_url_helper(mod, route, name, opts, route_key, url_strategy)
helper = UrlHelper.create(route, opts, route_key, url_strategy)
mod.module_eval do
define_method(name) do |*args|
last = args.last
options = \
case last
when Hash
args.pop
when ActionController::Parameters
args.pop.to_h
end
helper.call self, args, options
end
end
end
ここでさらに UrlHelper
というのが出てくる。
# actionpack/lib/action_dispatch/routing/route_set.rb
def initialize(route, options, route_name, url_strategy)
@options = options
@segment_keys = route.segment_keys.uniq
@route = route
@url_strategy = url_strategy
@route_name = route_name
end
def call(t, args, inner_options)
controller_options = t.url_options
options = controller_options.merge @options
hash = handle_positional_args(controller_options,
inner_options || {},
args,
options,
@segment_keys)
t._routes.url_for(hash, route_name, url_strategy)
end
handle_positional_args… (そろそろメタっぽいコードを見るのが辛くなってきた)
# actionpack/lib/action_dispatch/routing/route_set.rb
def handle_positional_args(controller_options, inner_options, args, result, path_params)
if args.size > 0
# take format into account
if path_params.include?(:format)
path_params_size = path_params.size - 1
else
path_params_size = path_params.size
end
if args.size < path_params_size
path_params -= controller_options.keys
path_params -= result.keys
end
inner_options.each_key do |key|
path_params.delete(key)
end
args.each_with_index do |arg, index|
param = path_params[index]
result[param] = arg if param
end
end
result.merge!(inner_options)
end
本気で困ったときにもう一回見直すことにしよう・・。