假设我有以下代码:
@sites = Site.find(session[:sites]) # will be an array of Site ids
@languages = Language.for_sites(@sites)
for_sites是语言模型中的named_scope,它返回与这些网站关联的语言,语言与使用has_many的网站相关联。目标是让@languages拥有与网站相关的独特语言数组。
我最好不要在第二行调用Language对象,而是想说
@sites.languages
并将相同的列表返回给我。有没有办法在Rails 2.1(或边缘)中干净利落地做到这一点?我知道关联和命名范围可以扩展数组对象以具有属性,但除非我遗漏了一些不适用于此处的内容。任何这样做的插件都是受欢迎的,它不一定是核心。
答案 0 :(得分:3)
您可以扩展Site.find返回的数组。
class Site
def find(*args)
result = super
result.extend LanguageAggregator if Array === result
result
end
end
module LanguageAggregator
def languages
Language.find(:all, :conditions => [ 'id in (?)', self.collect { |site| site.id } ])
end
end
答案 1 :(得分:2)
为什么不同时使用named_scopes?
class Site
named_scope :sites, lambda{|ids| :conditions => "id in (#{ids.join(',')})"}
named_scope :languages, :include => :languages ... (whatever your named scope does)
end
呼叫:
Site.sites(session[:sites]).languages
或者,如果你想要语言对象回来
Site.sites(session[:sites]).languages.collect{|site| site.languages}.flatten
您也可以直接在Language对象上执行此操作。 我正在使用:join,因为Rails 2.1拆分并且:包含在两个查询中,这意味着我们不能在:conditions中使用站点
class Language
named_scope :for_sites, lambda{|site_ids| :joins => 'inner join sites on languages.site_id = sites.id' :conditions => "sites.id in (#{site_ids.join(',')})"}
end
呼叫:
Language.for_sites(session[:sites])
在这两个例子中,我假设会话[:sites]完全由你控制,不受SQL注入。如果没有,请确保您处理清理ID的
答案 2 :(得分:0)
你的实例变量@sites是一个Array对象,而不是Site,所以我不认为可以使用named_scope。您可以打开Array类来实现此效果(yikes)
class Array
def languages
...
end
end
答案 3 :(得分:0)
如果您向网站添加了has_many
或has_and_belongs_to_many
个链接语言,那么您可以使用包含并执行以下操作:
Site.find( :all, :conditions =>{:id => session[:sites]}, :include => :languages )
您可以将命名范围设为:id =>会话[:sites]的事情,例如:
class Site
named_scope :for_ids, lambda{ |x| {:conditions => {:id => x }
end
然后再做
Site.for_ids(session[:sites]).find(:all, :include => :languages)
希望这会给你一些想法