ruby-on-rails - query - rails where
Refactoring has_many con ámbitos (1)
Soy un novato y simplemente le mostré mi código a un experto, que me dijo que no debería usar has_many
para filtrar mis variables, sino los scopes
.
Tengo tres modelos: Usuario, Producto y Propiedad.
Así que aquí está mi código en la aplicación / models / user.rb :
class User
has_many :ownerships, foreign_key: "offerer_id",
dependent: :destroy
has_many :owned_products, through: :ownerships,
source: :product
has_many :future_ownerships, -> { where owning_date: nil, giving_date: nil },
class_name: "Ownership",
foreign_key: "offerer_id"
has_many :wanted_products, through: :future_ownerships,
source: :product
end
Así que has_many :future_ownerships
el has_many :future_ownerships
y has_many :wanted_products
, y creé un alcance en app / models / ownership.rb :
class Ownership
scope :future, -> { where owning_date: nil, giving_date: nil }
end
Ahora puedo encontrar las futuras propiedades haciendo esto: user.ownerships.future
. Pero lo que no sé, ¿es cómo recuperar los productos deseados? ¿Cómo puedo hacer un alcance en mi aplicación / models / product.rb para poder escribir algo así?
user.owned_products.wanted
No hay nada inherentemente malo con las condiciones en sus asociaciones, especialmente si necesita cargar un subconjunto de productos.
Sin embargo, para lograr el alcance que necesita, debe agregarlo en el modelo de Product
y recurrir a sql simple ya que el filtro se aplica en un modelo diferente al definido.
class Product
# not tested
scope :wanted, ->{ where("ownerships.owning_dates IS NULL AND ...") }
end
En mi humilde opinión, está mejor con la primera solución. La razón es que si por algún motivo aplicas ese alcance dentro de un bloque de muchos usuarios, alcanzarás el muro de O (n) a pesar de estar ansioso por cargar los productos.
User.includes(:owned_products).each do |user|
user.onwned_products.wanted # => SQL connection
end
Actualización : acaba de descubrir la merge
una característica increíblemente indocumentada de ActiveRecord .
Entre otros usos, le permite hacer una combinación y filtrar por un alcance nombrado en el modelo unido
En otras palabras, puedes hacer:
user.owned_products.merge(Ownership.future)
¡Deja de ser poderoso!