リファレンス読んでもいまいちわからなかったので、そういうときは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
本気で困ったときにもう一回見直すことにしよう・・。