Что эквивалентно опции has_many 'conditions' в Rails 4?
Может ли кто-нибудь сказать мне, что эквивалентно, чтобы сделать следующую строку в Rails 4?
has_many :friends, :through => :friendships, :conditions => "status = 'accepted'", :order => :first_name
Я попробовал следующее:
has_many :friends, -> { where status: 'accepted' }, :through => :friendships , :order => :first_name
Но я получаю следующую ошибку:
Invalid mix of scope block and deprecated finder options on ActiveRecord association: User.has_many :friends
Ответы
Ответ 1
Нужно быть вторым аргументом arg:
class Customer < ActiveRecord::Base
has_many :orders, -> { where processed: true }
end
http://edgeguides.rubyonrails.org/association_basics.html#scopes-for-has-many
ОТВЕТ НА ОБНОВЛЕНИЕ:
Поместите порядок внутри блока:
has_many :friends, -> { where(friendship: {status: 'accepted'}).order('first_name DESC') }, :through => :friendships
Ответ 2
В то время как другие ответы здесь технически правильны, они нарушают инкапсуляцию. Модель пользователя не должна знать, что модель дружбы имеет столбец с именем status
и что он может иметь определенное значение, например accepted
.
Если вы решите внести изменения, например, воспользоваться Enums в Rails 4, вам придется изменить модели пользователя и дружбы. Это может привести к ошибкам, предотвращающим сохранение инкапсуляции.
Я бы выставил масштаб в модели Дружбы:
scope :accepted, -> { where(status: :accepted) }
Затем я использовал эту область в модели User, скрывая все детали реализации от пользователя.
has_many :friendships, -> { Friendship.accepted }
has_many :friends, through: :friendships
# Or...
has_many :friends, -> { Friendship.accepted }, through: :friendships
Вы можете перейти дальше и переименовать область accepted_friendships
, чтобы быть более четкой.
has_many :accepted_friendships, -> { Friendship.accepted }
has_many :friends, through: :accepted_friendships
Теперь вы успешно инкапсулировали детали реализации в своих соответствующих моделях. Если что-то изменится, у вас будет только одно место, чтобы изменить его, уменьшив обслуживание и повысив надежность.
Ответ 3
A Rails 3.2 версия ответа Мохамада будет следующей:
class Friend < ActiveRecord::Base
has_many :friendships, :order => :first_name
has_many :friends, :through => :friendships,
:conditions => proc { Friendship.accepted.where_ast }
has_many :pending_friends, :through => :friendships,
class_name => Friend,
:conditions => proc { Friendship.pending.where_ast }
end
class Friendship < ActiveRecord::Base
scope :status, ->(status) { where(:status => status) }
scope :accepted, -> { status('accepted') }
scope :pending, -> { where(arel_table[:status].not_eq('accepted')) }
end
ПРИМЕЧАНИЯ:
-
where_ast
важно, поскольку он возвращает узлы AREL, необходимые для работы условия
- внутри proc, переданного в
:conditions
, self
не всегда является экземпляром модели (например, когда объединение сливается с другим запросом)
- Использование raw SQL в ваших областях и ассоциациях, вероятно, вызовет проблемы в какой-то момент, связанные с пространством имен имен таблиц... используйте AREL.
Ответ 4
Чтобы работать с Rails 4.1 (мой случай), мне пришлось поставить:
has_many :friends, -> { where(friendships: { status: 'accepted' }) }, through: :friendships
Обратите внимание на S в дружбе. Он ссылается непосредственно на имя базы данных.
Ответ 5
has_many :friends, -> { where(status: 'accepted').order('frist_name')}, through: :friendships
или
has_many :friends, -> { where(status: 'accepted').order(:frist_name)}, through: :friendships