2010-01-29 80 views
5

假设我有这样的多态结构。Rails - 简洁地找到多态嵌套资源的父资源

map.resources :bar, :has_many => :foo 
map.resources :baz, :has_many => :foo 
map.resources :qux, :has_many => :foo 

class Foo 
    belongs_to :parent, :polymorphic => true 
end 

class FooController < AC 
before_filter :find_parent 

... 

private 
def find_parent 
    # ugly way: 
    @parent = if params[:bar_id] 
    Bar.find(params[:bar_id]) 
    elsif params[:baz_id] 
    Baz.find(params[:baz_id]) 
    elsif params[:qux_id] 
    Qux.find(params[:qux_id]) 
    end 
end 
end 

这很丑陋。每当我们添加一个它可能属于的新东西时,我们需要将它非干涉地添加到before_filter。

它也变得更糟。假设Foos是真的多态的东西,可以出现在任何地方,如评论或标签。而假设你有以下途径:

map.resources :bar, :has_many => :foo do |bar| 
bar.resources :baz, :has_many => :foo 
end 
map.resources :qux, :has_many => :foo do |qux| 
qux.resources :baz, :has_many => :foo 
end 

...现在我们不得不担心是否检查bar_id或baz_id第一。

对于更复杂的资源,这可能甚至不足以确保您获得父母的ID。

什么是理想的是,如果我们可以做这样的事情:

def get_parent 
# fetch the parameter that immediately preceeded :id 
@parent = if x = params.before(:id) 
    # polymorphic find 
    x.key.to_s[0..-4].classify.constantize.find x.value 
end 
end 

毕竟,我们的路线已经凭借在URL参数的顺序进行编码的父母。为什么要丢弃这些信息?

所以:这个怎么办?

+0

你最终找到一个DRY的方式来做到这一点? – hornairs 2010-07-07 01:05:44

回答

4

你应该能够索要foo.parent

你需要有这样的事情:

class Bar < ActiveRecord::Base 
    has_many :foos, :as => :parent 
    ... 
end 
+0

是的,这样你一定知道你得到了你的foo的真正父母。由于用户可以将任何内容传递给url,并且您可以获得任何定义的Foo的Bar/Baz/Qux)。 – Eimantas 2010-01-29 06:03:53

+0

这不一定适用于has_many polymorphy的某些类型,并且对于新记录它根本不起作用。 对于前者,假设Bar和Baz之间共享一个Foo,并且我需要告诉(对于特定的请求)哪一个是有效的。 – Sai 2010-01-29 22:34:11

+0

也不适用于FooController#索引(它需要知道要查询哪个父级的foos)。 – Sai 2010-01-30 01:48:14