给定一组ActiveRecord对象,我可以通过方法调用轻松收集它们的关系吗?

StackOverflow https://stackoverflow.com/questions/220126

假设我有以下代码:

@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(或边缘)中干净利落地做到这一点?我知道关联和命名范围可以扩展数组对象以具有属性,但除非我遗漏了一些不适用于此处的内容。任何这样做的插件都是受欢迎的,它不一定是核心。

有帮助吗?

解决方案

您可以扩展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

其他提示

为什么不同时使用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的

你的实例变量@sites是一个Array对象,而不是Site,所以我不认为可以使用named_scope。您可以打开Array类来实现此效果(yikes)

class Array

  def languages
    ...
  end

end

如果您添加了 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)

希望这会给你一些想法

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top