ruby on rails - quimica - ¿Cómo paso un argumento a un ámbito de asociación has_many en Rails 4?
ruby on rails que es (3)
La forma es definir un selector adicional extendido para el alcance de has_many
:
class Customer < ActiveRecord::Base
has_many :orders do
def by_account(account)
# use `self` here to access to current `Customer` record
where(:account_id => account.id)
end
end
end
customers.orders.by_account(account)
El enfoque se describe en el encabezado de Association Extension
de la Association
página de la Association
Rieles.
Para acceder al registro del Customer
en el método anidado, solo puede acceder al objeto self
, debe tener el valor del registro del Customer
actual.
Sinse of rails (aproximadamente 5.1), puede combinar el alcance de los modelos con el otro modelo tiene muchos alcances del mismo tipo, por ejemplo, puede escribir el mismo código de la siguiente manera en los dos modelos:
class Customer < ApplicationRecord
has_many :orders
end
class Order < ApplicationRecord
scope :by_account, ->(account) { where(account_id: account.id) }
end
customers.orders.by_account(account)
Rails 4 te permite ver una relación has_many
como esta:
class Customer < ActiveRecord::Base
has_many :orders, -> { where processed: true }
end
Así que en cualquier momento que hagas customer.orders
, solo recibirás pedidos procesados.
¿Pero qué pasa si necesito hacer que la condición de where
dinámica? ¿Cómo puedo pasar un argumento al alcance lambda?
Por ejemplo, solo quiero que se muestren los pedidos de la cuenta en la que el cliente está conectado actualmente en un entorno de múltiples inquilinos.
Esto es lo que tengo:
class Customer < ActiveRecord::Base
has_many :orders, (account) { where(:account_id => account.id) }
end
Pero, ¿cómo, en mi controlador o vista, paso la cuenta correcta? Con el código de arriba en su lugar cuando lo hago:
customers.orders
Recibo todos los pedidos por cuenta con un ID de 1, aparentemente arbitrariamente.
Pasas en una instancia de la clase que has definido. En su caso, pasaría a un cliente y luego obtendría la cuenta.
De la API Association
Accediendo al objeto propietario
A veces es útil tener acceso al objeto propietario al crear la consulta. El propietario se pasa como un parámetro al bloque. Por ejemplo, la siguiente asociación encontraría todos los eventos que ocurren en el cumpleaños del usuario:
class User < ActiveRecord::Base
has_many :birthday_events, ->(user) { where starts_on: user.birthday },
class_name: ''Event''
end
En tu ejemplo sería:
class Customer < ActiveRecord::Base
has_many :orders, ->(customer) { where(account_id: customer.account.id) }
end
Sé que esto es antiguo, pero como no se aceptó ninguna respuesta, pensé que agregar mis puntos de vista sobre el tema no perjudicaría a nadie.
El problema es que siempre que pase un alcance a una relación has_many
, pasar la instancia de la clase propietaria como un argumento no solo es una posibilidad, sino que es la única posibilidad de pasar un argumento. Quiero decir, no se le permite pasar más argumentos, y esta siempre será la instancia de la clase propietaria.
Así que @RobSobers, cuando tu
"obtener todos los pedidos por cuenta con un id de 1, aparentemente arbitrariamente".
no es arbitrario, usted recibe todos los pedidos con la id
del customer
que llamó la relación. Supongo que tu código era algo así como
Customer.first.orders(@some_account_which_is_ignored_anyway)
Parece que la relación has_many
no estaba destinada a aceptar argumentos.
Personalmente, prefiero la solución de @ МалъСкрылевъ.