假设我有一个包含 3 个模型的 Rails 应用程序:人、地点和事物。 假设 Thing 使用单表继承,因此有 FancyThing 和 ScaryThing 子类。 然后是用
map.resources :people, :places, :things
定义的路线。 因此,FancyThings 和 ScaryThings 没有控制器,ThingsController 可以处理任一类型。
现在假设我需要有代码来显示所有具有链接的内容的列表。 如果我认为有这段代码:
<% @items.each do |item| %>
<%= link_to item.name, item %>
<% end %>
如果项目是一个人或一个地方,这工作正常,
polymorphic_path
负责生成正确的路线。 但如果 item 是 FancyThing 或 ScaryThing,就会崩溃,因为它会尝试使用 fancy_thing_path
,而这是没有路径的。 我想以某种方式让它使用thing_path
。 理想情况下,Thing 和/或其子类上应该有一个方法,以某种方式指示子类应该使用基类来生成路由。 有一个优雅的解决方案吗?
这就能解决问题:
<% @items.map {|i| if i.class < Thing then i.becomes(Thing) else i end}.each do |item| %>
<%= link_to item.name, item %>
<% end %>
这使用 ActiveRecord 函数“成为”将 Thing 的所有子类“向上转换”到 Thing 基类。
尝试使用
map.resources :things
map.resources :fancy_things, :controller => 'things'
map.resources :scary_things, :controller => 'things'
没有正确的答案,但至少我可以使用非 DRY 代码来处理这个问题:
map.resources :things, :has_many => :stuffs map.resources :fancy_things, :controller => '东西', :has_many => :stuffs map.resources :scary_things, :controller => 'things', :has_many => :stuffs
希望这个问题能很快在 Edge 中得到纠正,因为我希望看到 fancy_things 仅由 :things 控制器管理。使用这些路由,您将以如下网址结尾:/fancy_things/1,而您可能想要/things/1
在路由文件中,您可以通过 Resolve 方法强制子类使用基类路由。 通过这种方式,您不会通过
becomes
调用污染其余代码(控制器、视图等)基础,并将其包含到路由文件中。
resolve("FancyThing") do |thing|
thing.becomes(Thing)
end
resolve("ScaryThing") do |thing|
thing.becomes(Thing)
end