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

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

Другие вопросы по тегам