Dado un conjunto de objetos ActiveRecord, ¿puedo recopilar fácilmente sus relaciones a través de una llamada de método?

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

Pregunta

Digamos que tengo el siguiente código:

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

for_sites es un named_scope en el modelo de idioma que devuelve los idiomas asociados con esos sitios, y los idiomas se asocian con los sitios que utilizan has_many. El objetivo es que @languages ??tenga una variedad distinta de los idiomas asociados con los sitios.

En lugar de llamar al objeto de idioma en la segunda línea, lo ideal sería decir

@sites.languages

y que me devuelvan la misma lista. ¿Hay alguna manera de hacerlo limpiamente en Rails 2.1 (o edge)? Sé que las asociaciones y los ámbitos con nombre pueden extender el objeto de matriz para tener atributos, pero a menos que me falte algo que no se aplique aquí. Cualquier complemento que haga esto sería bienvenido, no tiene que estar en el núcleo.

¿Fue útil?

Solución

Podría ampliar la matriz devuelta por 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

Otros consejos

¿Por qué no usar named_scopes para ambos?

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

llamada:

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

o, si quieres recuperar los objetos de lenguaje

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

También puedes hacerlo directamente en el objeto Idioma. Estoy usando: se une porque Rails 2.1 se divide y se incluye en dos consultas, lo que significa que no podemos usar sitios en las: condiciones

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

llamada:

Language.for_sites(session[:sites])

En ambos ejemplos, asumí que la sesión [: sitios] está completamente controlada por usted y no está sujeta a inyección SQL. Si no es así, asegúrese de tratar con la limpieza de las ID

Su variable de instancia @sites es un objeto Array y no un Sitio, por lo que no creo que se pueda usar named_scope. Sin embargo, puede abrir la clase Array para lograr este efecto (sí)

class Array

  def languages
    ...
  end

end

Si agregó un has_many o has_and_belongs_to_many vinculando los idiomas a los sitios, podría usar una inclusión y hacer algo como esto:

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

Puedes hacer un ámbito con nombre para hacer lo siguiente: id = > sesión [: sitios] cosa, por ejemplo:

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

y luego hazlo

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

Espero que esto te dé algunas ideas

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top