Подтвердить что ты не робот

Как передать аргумент в область объединения 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, кажущимся произвольным.

4b9b3361

Ответ 1

Способ состоит в том, чтобы определить дополнительный расширяющий селектор в области 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 head in Rails Association.

Чтобы получить доступ к записи Customer во вложенном методе, вы можете получить доступ к объекту self, он должен иметь значение текущей записи Customer.

Ответ 2

Вы передаете экземпляр класса, который вы определили. В вашем случае вы должны передать клиента, а затем получить учетную запись.

Из 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

Ответ 3

Я знаю, что это старо, но поскольку ответа еще не принято, я думал, что добавление моих взглядов на этот пункт никому не повредит.

Проблема заключается в том, что всякий раз, когда вы передаете область в отношение has_many, передача экземпляра класса владельца в качестве аргумента - это не только возможность, но только возможность передать аргумент. Я имею в виду, вам не разрешено передавать больше аргументов, и этот всегда будет экземпляром класса владельца.

Итак, @RobSobers, когда вы

"получить все заказы для учетной записи с идентификатором 1, казалось бы, произвольно.

он не является произвольным, вы получаете все порядки с th id из customer, который вы назвали отношением. Я предполагаю, что ваш код был чем-то вроде

Customer.first.orders(@some_account_which_is_ignored_anyway)

Похоже, что отношение has_many не предназначено для принятия аргументов.

Лично я предпочитаю решение @МалъСкрылевъ.