Tengo una matriz de objetos, llamémoslo un Indicator. Quiero ejecutar métodos de clase de indicador (los de la def self.subjectsvariedad, alcances, etc.) en esta matriz. La única forma que conozco de ejecutar métodos de clase en un grupo de objetos es que sean un ActiveRecord :: Relation. Entonces termino recurriendo a agregar un to_indicatorsmétodo a Array.
def to_indicators
# TODO: Make this less terrible.
Indicator.where id: self.pluck(:id)
end
A veces encadeno bastantes de estos ámbitos para filtrar los resultados, dentro de los métodos de clase. Entonces, aunque llamo a un método en un ActiveRecord :: Relation, no sé cómo acceder a ese objeto. Solo puedo acceder a su contenido all. Pero alles una matriz. Entonces tengo que convertir esa matriz en un ActiveRecord :: Relation. Por ejemplo, esto es parte de uno de los 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
Supongo que esto se condensa en dos preguntas.
- ¿Cómo puedo convertir una matriz de objetos en un ActiveRecord :: Relation? Preferiblemente sin hacer una
wherecada vez. - Al ejecutar un
def self.subjectsmétodo de tipo en un ActiveRecord :: Relation, ¿cómo accedo a ese objeto ActiveRecord :: Relation?
Gracias. Si necesito aclarar algo, házmelo saber.
fuente

.all, simplemente use.scopedcomo indica la respuesta de Andrew Marshall (aunque en los rieles 4 funcionará.all). Si necesita convertir una matriz en una relación, se ha equivocado en algún lugar ...Respuestas:
No puede convertir un Array en un ActiveRecord :: Relation ya que un Relation es solo un constructor para una consulta SQL y sus métodos no operan con datos reales.
Sin embargo, si lo que quieres es una relación, entonces:
para ActiveRecord 3.x, no llame
ally, en su lugarscoped, llame , lo que devolverá una Relación que representa los mismos registros queallle daría en un Array.para ActiveRecord 4.x, simplemente llame
all, que devuelve una Relación.Cuando se llama al método en un objeto Relation,
selfes la relación (a diferencia de la clase de modelo en la que se define).fuente
class User; def self.somewhere; where(location: "somewhere"); end; end, entoncesUser.limit(5).somewherePuede convertir una matriz de objetos
arren un ActiveRecord :: Relation como este (suponiendo que sepa qué clase son los objetos, lo que probablemente sepa)Sin
whereembargo, debe usarla , es una herramienta útil que no debería ser reacio a usar. Y ahora tiene una línea que convierte una matriz en una relación.map(&:id)convertirá su matriz de objetos en una matriz que contiene solo sus identificaciones. Y pasar una matriz a una cláusula where generará una declaración SQL con unINaspecto similar a:Tenga en cuenta que el orden de la matriz se perderá , pero dado que su objetivo es solo ejecutar un método de clase en la colección de estos objetos, supongo que no será un problema.
fuente
where(id: arr.map(&:id))? Y estrictamente hablando, esto no convierte la matriz en una relación, sino que obtiene nuevas instancias de los objetos (una vez que se realiza la relación) con esos ID que pueden tener valores de atributo diferentes a las instancias que ya están en memoria en la matriz.Bueno, en mi caso, necesito convertir una matriz de objetos a ActiveRecord :: Relation , así como ordenar con una columna específica (Identificación por ejemplo). Como estoy usando MySQL, la función de campo podría ser útil.
El SQL se parece a:
Función de campo MySQL
fuente
ActiveRecord::Relationenlaza la consulta de la base de datos que recupera datos de la base de datos.Supongamos que tiene sentido, tenemos una matriz con objetos de la misma clase, entonces ¿con qué consulta se supone que los vinculamos?
Cuando corro
Aquí arriba,
usersdevuelve elRelationobjeto pero enlaza la consulta de la base de datos detrás de él y puede verlo,Por lo tanto, no es posible regresar
ActiveRecord::Relationde una matriz de objetos que es independiente de la consulta SQL.fuente
En primer lugar, esta NO es una fórmula mágica. Según mi experiencia, descubrí que convertir a una relación a veces es más fácil que las alternativas. Intento utilizar este enfoque con moderación y solo en los casos en que la alternativa sería más compleja.
Dicho esto, aquí está mi solución, he ampliado la
ArrayclaseUn ejemplo de uso sería
array.to_activerecord_relation.update_all(status: 'finished'). ¿Ahora dónde lo uso?A veces es necesario filtrar,
ActiveRecord::Relationpor ejemplo, eliminar elementos no completados. En esos casos, lo mejor es usar el alcanceelements.not_finishedy aún lo mantendríaActiveRecord::Relation.Pero a veces esa condición es más compleja. Sacar todos los elementos que no estén terminados, que hayan sido producidos en las últimas 4 semanas y hayan sido inspeccionados. Para evitar la creación de nuevos ámbitos, puede filtrar a una matriz y luego volver a convertir. Tenga en cuenta que aún realiza una consulta a DB, rápido ya que busca por
idpero sigue siendo una consulta.fuente