【问题标题】:What is the equivalent of the has_many 'conditions' option in Rails 4?Rails 4 中的 has_many 'conditions' 选项的等价物是什么?
【发布时间】:2013-12-01 01:55:59
【问题描述】:

谁能告诉我在 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

【问题讨论】:

  • 呃……你能把整个文件贴出来吗?我以前从未见过这个错误。
  • 呃,没关系,我想我知道出了什么问题,会更新......

标签: ruby-on-rails-4


【解决方案1】:

需要是第二个参数:

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

【讨论】:

  • 在第二个参数中替换它后,我收到此错误:ActiveRecord 关联中范围块和不推荐使用的查找器选项的无效混合:User.has_many:朋友
  • 你能用你尝试的方法更新你的问题吗?您的评论中似乎没有足够的空间。
  • 我用过这个 -> { where status: 'requested' , :order => :created_at} 它对我有用
  • 感谢您的帮助,请添加我的解决方案作为第二个建议^^
  • @medBo 我不确定您的解决方案是否符合您的想法。我认为它最终评估为where(status: 'requested', order: :created_at),而不是实际对关系应用顺序。您可以通过检查生成的 SQL (a_customer.friends.to_sql) 来验证这一点
【解决方案2】:

虽然此处的其他答案在技术上是正确的,但它们违反了封装。 User 模型不应该知道 Friendship 模型有一个名为 status 的列,并且它可以有一个特定的值,例如 accepted

如果您决定进行更改,例如,为了利用 Rails 4 中的枚举,您必须同时更改 UserFriendship 模型。这可能会导致维护封装避免的错误。

我将在 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

现在您已经成功地将实现细节封装在各自的模型中。如果发生任何变化,您只需在一个地方进行更改,从而减少维护并提高稳健性。

【讨论】:

  • 您的解决方案看起来更干净,我稍后会尝试。 +1
  • 我正在使用相同类型的代码,但使用此行得到syntax error, unexpected '\n', expecting =&gt;has_many :friends, :through =&gt; :friendships, class_name: "User", -&gt; { Friendship.accepted }
  • 我使用的是 Rails 4.2.5,直到我将 where 放在其余参数之前,它才接受语法
  • @Riptyde4 抱歉,我没有正确阅读您之前的评论:正如我的回答所示,proc (-&gt;{ Friendship.accepted }) 必须是第二个参数。所以是的,如果你没有按那个顺序,这将是一个语法错误。我的答案以正确的顺序显示:has_many :friends, -&gt; { Friendship.accepted }, through: :friendships
  • @Mohamad 很抱歉造成混乱,当我自己尝试时,我没有意识到顺序很重要。你的回答对我很有帮助
【解决方案3】:

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 的过程中,self 并不总是模型实例(例如,当关联与另一个查询合并时)
  • 在您的范围和关联中使用原始 SQL 可能会在某些时候导致与表名的命名空间有关的问题...使用 AREL。

【讨论】:

    【解决方案4】:

    为了在 Rails 4.1(我的情况)上工作,我不得不说:

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

    注意关于友谊的 S。它直接引用数据库名称。

    【讨论】:

      【解决方案5】:
      has_many :friends, -> { where(status: 'accepted').order('first_name')}, through: :friendships
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-08
        • 2010-10-03
        • 1970-01-01
        • 2022-07-31
        • 2011-08-29
        • 1970-01-01
        • 2020-02-02
        • 2020-05-16
        相关资源
        最近更新 更多