Dato un array di oggetti ActiveRecord, posso facilmente raccogliere le loro relazioni tramite una chiamata di metodo?

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

Domanda

Diciamo che ho il seguente codice:

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

for_sites è un nome_scope nel modello Lingua che restituisce le lingue associate a quei siti e le lingue sono associate ai siti che usano has_many attraverso. L'obiettivo è che @languages ??abbia una matrice distinta delle lingue associate ai siti.

Invece di chiamare l'oggetto Language sulla seconda riga, idealmente vorrei dire

@sites.languages

e mi viene restituito lo stesso elenco. C'è un modo per farlo in modo pulito in Rails 2.1 (o edge)? So che le associazioni e gli ambiti denominati possono estendere l'oggetto array per avere attributi, ma a meno che non manchi qualcosa che non si applica qui. Qualsiasi plugin che lo faccia sarebbe il benvenuto, non deve essere nel core.

È stato utile?

Soluzione

È possibile estendere l'array restituito da 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

Altri suggerimenti

Perché non usare named_scopes per entrambi?

class Site
  named_scope :sites, lambda{|ids| :conditions => "id in (#{ids.join(',')})"}
  named_scope :languages, :include => :languages ... (whatever your named scope does)
end

chiamata:

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

oppure, se si desidera ripristinare gli oggetti linguaggio

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

Puoi anche farlo direttamente sull'oggetto Lingua. Sto usando: si unisce perché Rails 2.1 si divide e include in due query, il che significa che non possiamo usare i siti nelle condizioni:

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

chiamata:

Language.for_sites(session[:sites])

In entrambi gli esempi ho ipotizzato che la sessione [: siti] sia completamente controllata da te e non soggetta all'iniezione SQL. In caso contrario, assicurati di occuparti della pulizia dell'ID

La variabile di istanza @sites è un oggetto Array e non Site, quindi non credo che si possa usare named_scope. Puoi aprire la classe Array per ottenere questo effetto (yikes)

class Array

  def languages
    ...
  end

end

Se hai aggiunto un has_many o has_and_belongs_to_many che collega le lingue ai siti, puoi utilizzare un include e fare qualcosa del genere:

Site.find( :all, :conditions =>{:id => session[:sites]}, :include => :languages )

Puoi creare un ambito denominato per eseguire: id = > sessione [: siti], ad esempio:

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

e poi

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

Spero che questo ti dia alcune idee

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top