Tengo una matriz de objetos, llamémoslo un Indicator
. Quiero ejecutar métodos de clase de indicador (los de la def self.subjects
variedad, 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_indicators
mé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 all
es 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
where
cada vez. - Al ejecutar un
def self.subjects
mé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.scoped
como 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
all
y, en su lugarscoped
, llame , lo que devolverá una Relación que representa los mismos registros queall
le 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,
self
es 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).somewhere
Puede convertir una matriz de objetos
arr
en un ActiveRecord :: Relation como este (suponiendo que sepa qué clase son los objetos, lo que probablemente sepa)Sin
where
embargo, 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 unIN
aspecto 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::Relation
enlaza 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,
users
devuelve elRelation
objeto pero enlaza la consulta de la base de datos detrás de él y puede verlo,Por lo tanto, no es posible regresar
ActiveRecord::Relation
de 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
Array
claseUn ejemplo de uso sería
array.to_activerecord_relation.update_all(status: 'finished')
. ¿Ahora dónde lo uso?A veces es necesario filtrar,
ActiveRecord::Relation
por ejemplo, eliminar elementos no completados. En esos casos, lo mejor es usar el alcanceelements.not_finished
y 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
id
pero sigue siendo una consulta.fuente