Eu tenho uma série de objetos, vamos chamá-la de Indicator
. Eu quero executar métodos de classe Indicator (aqueles da def self.subjects
variedade, escopos, etc) neste array. A única maneira que conheço de executar métodos de classe em um grupo de objetos é fazer com que sejam um ActiveRecord :: Relation. Então acabo recorrendo à adição de um to_indicators
método a Array
.
def to_indicators
# TODO: Make this less terrible.
Indicator.where id: self.pluck(:id)
end
Às vezes, eu encadeamento alguns desses escopos para filtrar os resultados, dentro dos métodos de classe. Portanto, embora eu chame um método em um ActiveRecord :: Relation, não sei como acessar esse objeto. Eu só consigo acessar o conteúdo dela all
. Mas all
é um Array. Então, eu tenho que converter esse array para um ActiveRecord :: Relation. Por exemplo, isso faz parte de um dos métodos:
all.to_indicators.applicable_for_bank(id).each do |indicator|
total += indicator.residual_risk_for(id)
indicator_count += 1 if indicator.completed_by?(id)
end
Acho que isso se resume a duas perguntas.
- Como posso converter um Array de objetos em um ActiveRecord :: Relation? De preferência sem fazer um a
where
cada vez. - Ao executar um
def self.subjects
método de tipo em um ActiveRecord :: Relation, como faço para acessar o próprio objeto ActiveRecord :: Relation?
Obrigado. Se eu precisar esclarecer alguma coisa, me avise.
fonte
.all
, apenas use.scoped
como indica a resposta de Andrew Marshall (embora no rails 4 funcione com.all
). Se você precisar transformar um array em uma relação, você errou em algum lugar ...Respostas:
Você não pode converter um Array em um ActiveRecord :: Relation, pois um Relation é apenas um construtor para uma consulta SQL e seus métodos não operam em dados reais.
No entanto, se o que você deseja é uma relação:
para ActiveRecord 3.x, não chame
all
e sim chamescoped
, o que retornará um Relation que representa os mesmos registros queall
você daria em um Array.para ActiveRecord 4.x, basta chamar
all
, que retorna uma relação.Quando o método é chamado em um objeto Relation,
self
é a relação (em oposição à classe de modelo em que é definida).fonte
class User; def self.somewhere; where(location: "somewhere"); end; end
, entãoUser.limit(5).somewhere
Você pode converter uma matriz de objetos
arr
em um ActiveRecord :: Relation como este (assumindo que você sabe a qual classe os objetos são, o que provavelmente você sabe)Você tem que usar
where
, porém, é uma ferramenta útil que você não deve hesitar em usar. E agora você tem uma linha convertendo um array em uma relação.map(&:id)
irá transformar seu array de objetos em um array contendo apenas seus ids. E passar uma matriz para uma cláusula where gerará uma instrução SQL com aIN
seguinte aparência:Lembre-se de que a ordem do array será perdida - mas como seu objetivo é apenas executar um método de classe na coleção desses objetos, presumo que não seja um problema.
fonte
where(id: arr.map(&:id))
? E estritamente falando, isso não converte a matriz em uma relação, mas em vez disso obtém novas instâncias dos objetos (uma vez que a relação é realizada) com aqueles IDs que podem ter valores de atributo diferentes das instâncias já na memória na matriz.Bem, no meu caso, eu preciso converter uma matriz de objetos para ActiveRecord :: Relation , bem como classificá- los com uma coluna específica (id por exemplo). Como estou usando o MySQL, a função de campo pode ser útil.
O SQL se parece com:
Função de campo MySQL
fonte
ActiveRecord::Relation
vincula consulta de banco de dados que recupera dados do banco de dados.Suponha que para fazer sentido, temos array com objetos da mesma classe, então com que consulta supomos ligá-los?
Quando eu corro,
Aqui acima,
users
retorna oRelation
objeto, mas vincula a consulta do banco de dados por trás dele e você pode visualizá-lo,Portanto, não é possível retornar
ActiveRecord::Relation
de um array de objetos que seja independente da consulta sql.fonte
Em primeiro lugar, esta NÃO é uma bala de prata. Com base na minha experiência, descobri que a conversão às vezes é mais fácil do que as alternativas. Tento usar essa abordagem com moderação e apenas nos casos em que a alternativa seria mais complexa.
Dito isso, aqui está a minha solução, estendi a
Array
aulaUm exemplo de uso seria
array.to_activerecord_relation.update_all(status: 'finished')
. Agora, onde eu uso?Às vezes, você precisa filtrar,
ActiveRecord::Relation
por exemplo, remover elementos não concluídos. Nesses casos, o melhor é usar o escopoelements.not_finished
e você ainda manteriaActiveRecord::Relation
.Mas às vezes essa condição é mais complexa. Retire todos os elementos que não estão acabados e que foram produzidos nas últimas 4 semanas e foram inspecionados. Para evitar a criação de novos escopos, você pode filtrar para uma matriz e depois converter de volta. Lembre-se de que você ainda faz uma consulta ao DB, rápido, pois ele pesquisa por,
id
mas ainda é uma consulta.fonte