如何在Rails中设置条件关联?

时间:2014-12-28 00:05:15

标签: ruby-on-rails activerecord associations

所以我有两个相关的模型用户和杂志。它们通过订阅与has_many:through关系相关联。所以这就是它的样子:

class User < ActiveRecord::Base
  has_many :subscriptions
  has_many :magazines, :through => :subscriptions
end

class Subscription < ActiveRecord::Base
  belongs_to :user
  belongs_to :magazine
end

class Magazine < ActiveRecord::Base
  has_many :subscriptions
  has_many :users, :through => :subscriptions
end    

用户有一个名为paid的布尔属性。我只希望paid == true的用户能够订阅任何杂志。如何设置这样的条件关联?在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

对于关联,您可以在哈希选项之前传递lambda。在这个lambda中,您可以指定条件,排序等。

class Magazine < ActiveRecord::Base
  has_many :subscriptions
  has_many :users, ->{ where(users: {paid: true}) }, through: :subscriptions
end 

对于用户,您可以这样做:

class User < ActiveRecord::Base
  has_many :subscriptions
  has_many :magazines, through: :subscriptions

  def magazines
    self.paid ? super : Magazine.none
  end
end

虽然它很整洁,但当您加入表格时,上述情况可能会出现不可预测的情况,例如: User.joins(:magazines)可能会忽略paid条件或崩溃。

更好的选择:

class User < ActiveRecord::Base
  has_many  :subscriptions
  has_many  :magazines,
            ->{ where("subscriptions.user_id IN (
                  SELECT id FROM users WHERE users.paid = 't')") },
            through: :subscriptions
end

lambda中的where可以由joins替换,如下所示:

joins(subscriptions: :user).where(users: {paid: true})

但我认为'加入subscriptions两次 - 一次是lambda,一次是关联。我不确定。如果是这样,如果这困扰你,那么:

joins("INNER JOIN users ON (users.id = subscriptions.user_id)").
where(users: {paid: true})

或:

joins("INNER JOIN users ON (
  (users.id = subscriptions.user_id) AND (users.paid = 't')
)")

此外,我认为您将Subscription模型标记为Registration