rails query left joins includes active ruby-on-rails scope model-associations

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!