Rails 4中has_many'条件'选项的等价物是什么?

时间:2013-12-01 01:56:00

标签: ruby-on-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

5 个答案:

答案 0 :(得分:109)

需要成为第二个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

答案 1 :(得分:51)

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

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

我会在友谊模型中公开一个范围:

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

现在,您已在各自的模型中成功封装了实施细节。如果有任何改变,你只有一个地方可以改变它,减少维护并提高稳健性。

答案 2 :(得分:4)

Mohamad的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节点
  • 传递给:conditions的proc中的
  • self并不总是模型实例(例如,当关联与其他查询合并时)
  • 在您的范围和关联中使用原始SQL可能会在某些时候引起与表名的命名空间有关的问题...使用AREL。

答案 3 :(得分:2)

为了处理 Rails 4.1 (我的情况),我不得不提出:

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

注意S对友谊的看法。它直接引用数据库名称。

答案 4 :(得分:0)

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

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