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

Ruby on rails 给定一个ActiveRecord对象数组,我可以通过方法调用轻松收集它们的关系吗?,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,假设我有以下代码: @sites = Site.find(session[:sites]) # will be an array of Site ids @languages = Language.for_sites(@sites) for_sites是语言模型中的一个命名_作用域,它返回与这些站点关联的语言,并且语言与使用has_many到的站点关联。我们的目标是@languages拥有一个与站点相关联的独特的语言数组 理想情况下,我想说 @sites.languages 把同样的清单还给

假设我有以下代码:

@sites = Site.find(session[:sites]) # will be an array of Site ids
@languages = Language.for_sites(@sites)
for_sites是语言模型中的一个命名_作用域,它返回与这些站点关联的语言,并且语言与使用has_many到的站点关联。我们的目标是@languages拥有一个与站点相关联的独特的语言数组

理想情况下,我想说

@sites.languages

把同样的清单还给我。在Rails 2.1(或edge)中有没有任何方法可以干净地做到这一点?我知道关联和命名作用域可以扩展数组对象以使其具有属性,但除非我缺少一些不适用于此处的内容。任何这样做的插件都是受欢迎的,它不必在核心中。

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


如果您添加了一个
has\u many
has\u且\u属于\u many
链接语言到站点,那么您可以使用include并执行以下操作:

Site.find( :all, :conditions =>{:id => session[:sites]}, :include => :languages )
您可以创建一个命名范围来执行:id=>session[:sites]操作,例如:

class Site
  named_scope :for_ids, lambda{ |x| {:conditions => {:id => x }
end
然后呢

Site.for_ids(session[:sites]).find(:all, :include => :languages)

希望这能给你一些想法

为什么不同时使用命名范围呢

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.collect{|site| site.languages}.flatten
也可以直接在Language对象上执行此操作。 我之所以使用:连接,是因为Rails2.1将:拆分为两个查询,这意味着我们不能在:条件下使用站点

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
电话:


在这两个示例中,我假设会话[:sites]完全由您控制,不受SQL注入的约束。如果没有,请确保已清理ID的

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

没错,我知道Rails以一种可扩展的方式为某些其他对象(比如从has_许多关联返回的数组)实现了这一点。我希望会有更干净一点的。谢谢你的回答!我知道我可以:include=>languages,但这并不是我想要的——我基本上是在寻找一个不同的语言列表,给出一个网站集合。而find([array of id])已经返回了这些站点,所以我认为这对我来说没有多大好处。。。谢谢你的回答!您的第二次尝试实际上非常接近(只需要一个.uniq调用),但我有点希望我可以得到一些语法糖,以获得美妙的Ruby新鲜感。你的语言理念基本上就是我现在所拥有的,尽管有点不同,因为我有一个站点语言模型。谢谢你!啊,其他的方法就是这样做的。。。谢谢,这绝对是最接近的,甚至看起来它可以被提取出来成为一个模块和/或插件。
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])
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