Rails 4中的has_many'conditions'选项等价于什么?

有人可以告诉我什么是在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 

需要成为第二个参数:

 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 

虽然这里的其他答案在技术上是正确的,但它们违反了封装。 用户模型不应该知道友谊模型有一个称为status的列,并且它可以具有特定的值,如accepted

如果您决定进行更改,例如要利用Rails 4中的Enums,则必须更改UserFriendship模型。 这可能会导致错误,保持封装避免。

我将在友谊模型中展示一个范围:

 scope :accepted, -> { where(status: :accepted) } 

然后我会在User模型中使用这个范围,隐藏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 

现在,您已经成功地在各自的模型中封装了实现细节。 如果有什么改变,你只有一个地方来改变它,减less维护和增加健壮性。

Rails 3.2版本的Mohamad回答如下:

 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节点
  • 在传递给:conditionsself并不总是模型实例(例如,当关联与另一个查询合并时)
  • 在您的作用域和关联中使用原始SQL可能会导致某些问题与表名的命名空间有关…使用AREL。

为了使用Rails 4.1 (我的情况),我不得不把:

 has_many :friends, -> { where(friendships: { status: 'accepted' }) }, through: :friendships 

注意S上的友谊。 它直接指向数据库名称。

 has_many :friends, -> { where(status: 'accepted').order('frist_name')}, through: :friendships 

要么

 has_many :friends, -> { where(status: 'accepted').order(:frist_name)}, through: :friendships