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



假设我有以下代码:

@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 对象上执行此操作。我正在使用 :joins,因为 Rails 2.1 拆分和 :include 分为两个查询,这意味着我们不能在 :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])

在这两个例子中,我假设session[:sites]完全由你控制,不受SQL注入的影响。如果没有,请确保您处理清理 ID 的

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

class Array
  def languages
    ...
  end
end

如果您添加了将语言链接到站点has_manyhas_and_belongs_to_many,则可以使用包含并执行以下操作:

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)

希望这能给你一些想法

相关内容

  • 没有找到相关文章

最新更新