Имея массив объектов ActiveRecord, могу ли я легко собрать их отношения с помощью вызова метода? - PullRequest
2 голосов
/ 21 октября 2008

Допустим, у меня есть следующий код:

@sites = Site.find(session[:sites]) # will be an array of Site ids
@languages = Language.for_sites(@sites)

for_sites - это named_scope в модели Language, которая возвращает языки, связанные с этими сайтами, а языки связываются с сайтами, использующими has_many через. Цель состоит в том, чтобы @languages ​​имел отдельный массив языков, связанных с сайтами.

Вместо вызова объекта Language во второй строке, в идеале я бы хотел сказать

@sites.languages

и мне возвращают тот же список. Есть ли способ сделать это чисто в Rails 2.1 (или edge)? Я знаю, что ассоциации и именованные области могут расширять объект массива, чтобы иметь атрибуты, но если я не пропущу то, что здесь не применимо. Любые плагины, которые делают это, приветствуются, они не обязательно должны быть в ядре.

Ответы [ 4 ]

3 голосов
/ 23 октября 2008

Вы можете расширить массив, возвращаемый 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
2 голосов
/ 21 октября 2008

Почему бы не использовать 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. Я использую: соединения, потому что Rails 2.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

по телефону:

Language.for_sites(session[:sites])

В обоих примерах я предположил, что сессия [: sites] полностью контролируется вами и не подлежит внедрению SQL. Если нет, убедитесь, что вы справляетесь с очисткой идентификатора

0 голосов
/ 21 октября 2008

Если вы добавили has_many или has_and_belongs_to_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)

Надеюсь, что это дает вам некоторые идеи

0 голосов
/ 21 октября 2008

Ваша переменная экземпляра @sites является объектом Array, а не Site, поэтому я не думаю, что named_scope можно использовать. Вы можете открыть класс Array для достижения этого эффекта (yikes)

class Array

  def languages
    ...
  end

end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...