有谁知道它是如何工作的,最重要的是如何覆盖它?
我从事一个 Rails 5.0.0.1 项目。出于实际原因,我们使用命名空间路由,例如
namespace :survey do
resources :questions
resources :answers
end
我们相应地Question
和Answer
模型。
文档告诉我们,帮助程序link_to
可以简单地将 ActiveRecord 实例作为第二个参数传递,这意味着在我的情况下只需在视图 (haml) 中编写以下内容:
= link_to 'Show question', @question
如果没有命名空间,这工作正常,但适用于命名的帮助程序方法question_path
即使路由是命名空间的 - 而不是survey_question_path
。关键是我想从 ActiveRecord 实例中决定使用哪个命名路由帮助程序。
有趣的是,Rails 知道 Question 实例将有一个命名路由,类似question_path,我只是不知道怎么做。
到目前为止,我发现了什么:
link_to
的第二个参数使用一个辅助方法url_for
,然后选择适当的(或不)命名的路由帮助程序 - 但是如何呢?- ActiveRecord 实例具有方法
model_name
,其中包含route_key
(复数)和singular_route_key
等属性 - 我不确定这是否与我正在寻找的内容有关,或者即使它有如何覆盖它。
我认为有一个简单的方法可以在模型中覆盖,例如to_partial_path
用于render @question
,或者在控制器的情况下self.controller_path
从另一个视图目录渲染操作,但我找不到它。
任何帮助将不胜感激。
编辑
经过更多的谷歌搜索,我偶然发现了APIdock中的以下段落(依赖于命名路由):
传递记录(如
Active Record
)而不是哈希作为选项参数将触发该记录的命名路由。查找将在类的名称上进行。因此,传递创意工坊对象将尝试使用workshop_path
路由。如果你有一个嵌套的路由,比如admin_workshop_path
你必须显式调用它(url_for
不可能猜到那个路由)。
Rails 使用模型的model_name
,就是这样,你不应该覆盖该方法。如果你想把一个Question
变成对survey_question_path
的调用,那么你需要定义你自己的question_path
,它返回survey_question_path
......
def question_path(question)
survey_question_path(question)
end
。或者只是自己使用完整的方法名称。
您还可以使用符号/模型数组,这些数组直接传递给url_for
:
= link_to 'Show question', [:survey, @question]
至于你的问题:
- link_to 的第二个参数使用帮助程序方法url_for,它 然后选择适当(或不)命名的路由助手 - 但是如何?
如果你遵循你在源代码周围提到的#url_for方法,我们就会被扔掉,从ActionView::RoutingUrlFor到ActionDispatch::Routing::P olymorphicRoutes
(资料来源:https://github.com/rails/rails/blob/870dde4710f1492c83233620f343ec414a07a950/actionview/lib/action_view/routing_url_for.rb#L115)。
在ActionDispatch::Routing::P olymorphicRoutes#polymorphic_url方法中,它使用内部类并调用HelperMethodBuilder.polymorphic_method,将所有给定的选项(包括您的模型类作为"record_or_hash_or_array"传递(是的,我知道...))。
下面几行,在这个方法的声明中,你会更多地使用小方法,最终得到这样的方法:
def self.build(action, type)
prefix = action ? "#{action}_" : ""
suffix = type
if action.to_s == "new"
HelperMethodBuilder.singular prefix, suffix
else
HelperMethodBuilder.plural prefix, suffix
end
end
def self.singular(prefix, suffix)
new(->(name) { name.singular_route_key }, prefix, suffix)
end
def self.plural(prefix, suffix)
new(->(name) { name.route_key }, prefix, suffix)
end
(来源:https://github.com/rails/rails/blob/3f2b7d60a52ffb2ad2d4fcf889c06b631db1946b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb)
如您所见,它将决定是否是#new操作,并调用#singular或#plural,这将反过来回答您的第二个问题:
- ActiveRecord 实例具有方法 model_name,其中包含route_key(复数)和 singular_route_key 等属性 - 我不确定这是否与我正在寻找的内容有关,或者即使它有如何覆盖它。
正如我们在上面看到的,这两个方法被分配给一个 lambda,该 lambda 是这个内部类的初始值设定项的第一个参数,它将存储为@key_strategy。回到**ActionView#UrlFor"中,在我向您展示的第一个链接上,您会看到以下调用:
else
builder.handle_model_call(self, options)
这将传递给构建器端的几个方法:
def handle_model(record)
args = []
model = record.to_model
named_route = if model.persisted?
args << model
get_method_for_string model.model_name.singular_route_key
else
get_method_for_class model
end
[named_route, args]
end
def handle_model_call(target, model)
method, args = handle_model model
target.send(method, *args)
end
private
def get_method_for_class(klass)
name = @key_strategy.call klass.model_name
get_method_for_string name
end
def get_method_for_string(str)
"#{prefix}#{str}_#{suffix}"
end
而且,如果我没有错过任何内容,最后一种方法将返回您的 URL 路径。