Как передать аргумент в область ассоциации has_many в Rails 4?
Rails 4 позволяет вам охватывать has_many
отношения вроде так:
class Customer < ActiveRecord::Base
has_many :orders, -> { where processed: true }
end
Так что в любое время вы делаете customer.orders
Вы получаете только обработанные заказы.
Но что, если мне нужно сделать where
состояние динамическое? Как я могу передать аргумент в область лямбда?
Например, я хочу, чтобы заказы отображались только для учетной записи, в которую в данный момент входит клиент в многопользовательской среде.
Вот что у меня есть:
class Customer < ActiveRecord::Base
has_many :orders, (account) { where(:account_id => account.id) }
end
Но как, в моем контроллере или представлении, я передаю правильный счет? С кодом выше на месте, когда я делаю:
customers.orders
Я получаю все заказы на аккаунт с идентификатором 1, казалось бы, произвольно.
3 ответа
Способ заключается в том, чтобы определить дополнительный расширяющий селектор 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)
Подход описан в Association Extension
голова в рельсах Association
стр.
Чтобы получить доступ к Customer
запись во вложенном методе вы можете просто получить доступ self
объект, он должен иметь значение текущего Customer
запись.
С помощью рельсов (около 5.1) вы можете объединить область видимости моделей с областью действия типа has_many другой модели, например, вы можете написать один и тот же код следующим образом в двух моделях:
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)
Вы передаете экземпляр класса, который вы определили. В вашем случае вы должны передать клиента, а затем получить учетную запись.
Из API http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Доступ к объекту владельца
Иногда полезно иметь доступ к объекту владельца при построении запроса. Владелец передается в качестве параметра в блок. Например, следующая ассоциация найдет все события, которые происходят в день рождения пользователя:
class User < ActiveRecord::Base
has_many :birthday_events, ->(user) { where starts_on: user.birthday },
class_name: 'Event'
end
В вашем примере это будет:
class Customer < ActiveRecord::Base
has_many :orders, ->(customer) { where(account_id: customer.account.id) }
end
Я знаю, что это старо, но так как ответ еще не был принят, я думал, что добавление моих взглядов по этому вопросу никому не повредит.
Проблема в том, что всякий раз, когда вы передаете has_many
отношения, передача экземпляра класса владельца в качестве аргумента - это не только возможность, но и единственная возможность передать аргумент. Я имею в виду, вам не разрешено передавать больше аргументов, и этот всегда будет экземпляром класса владельца.
Так @RobSobers, когда ты
"получить все заказы на счет с идентификатором 1, казалось бы, произвольно."
это не произвольно, вы получаете все заказы с id
из customer
Вы назвали отношения на. Я думаю, что ваш код был что-то вроде
Customer.first.orders(@some_account_which_is_ignored_anyway)
Похоже на has_many
отношение не должно было принимать аргументы.
Лично я предпочитаю решение @МалъСкрылевъ.