Dado um conjunto de ActiveRecord objetos, eu posso facilmente recolher as suas relações através de uma chamada de método?

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

Pergunta

Vamos dizer que eu tenho o seguinte código:

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

for_sites é um named_scope no modelo de linguagem que retorna as línguas associados a esses locais e idiomas estão associados a sites usando has_many através. O objetivo é que @languages ??ter uma matriz distinta das línguas associados com os sites.

Em vez de chamar o objeto Idioma na segunda linha, eu idealmente gostaria de dizer

@sites.languages

e ter a mesma lista voltou para mim. Existe alguma maneira de fazer isso de forma limpa no Rails 2.1 (ou EDGE)? Eu sei associações e escopos nomeados pode estender o objeto de matriz para ter atributos, mas a menos que eu estou faltando alguma coisa que não se aplica aqui. Quaisquer plugins que fazem isso seria bem-vinda, ele não tem que estar no núcleo.

Foi útil?

Solução

Você poderia estender a matriz retornada 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

Outras dicas

Por que não 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

chamada:

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

ou, se você quiser linguagem objetos de volta

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

Você também pode fazê-lo diretamente no objeto Idioma. Eu estou usando: junta porque Rails 2.1 divide e: incluem em duas consultas que significa que não pode usar sites nos: condições

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

chamada:

Language.for_sites(session[:sites])

Em ambos os exemplos que eu assumir que sessão [:] locais é totalmente controlado por você e não sujeito a injeção de SQL. Se não, certifique-se de lidar com a limpeza do ID

Seus @sites variável da instância é um objeto Array e não do site, então eu não acho que named_scope pode ser usado. Você pode abrir classe Array para conseguir este efeito embora (yikes)

class Array

  def languages
    ...
  end

end

Se você adicionou um has_many ou has_and_belongs_to_many ligando idiomas em sites, em seguida, você poderia usar um incluem e fazer algo como isto:

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

Você pode fazer um escopo nomeado para fazer o: id => session [: Locais] coisa, por exemplo:

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

e, em seguida, fazer

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

Espero que isso lhe dá algumas idéias

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top