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 throughを使用してサイトに関連付けられます。目標は、@ languagesがサイトに関連付けられた言語の明確な配列を持つことです。

2行目の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

call:

Site.sites(session[:sites]).languages

または、言語オブジェクトを戻す場合

Site.sites(session[:sites]).languages.collect{|site| site.languages}.flatten

言語オブジェクトで直接行うこともできます。 Rails 2.1が:includesを2つのクエリに分割し、:conditionsでサイトを使用できないことを意味するため、私は:joinsを使用しています

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

call:

Language.for_sites(session[:sites])

どちらの例でも、session [:sites]は完全に制御され、SQLインジェクションの対象ではないと想定しました。そうでない場合は、IDのクリーンアップに対処してください

インスタンス変数@sitesはSiteではなくArrayオブジェクトなので、named_scopeを使用できるとは思いません。ただし、Arrayクラスを開いてこの効果を得ることができます(いいね)

class Array

  def languages
    ...
  end

end

言語をサイトにリンクする has_many または has_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)

これがあなたにいくつかのアイデアを与えることを願っています

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top