【问题标题】:How can I set up conditional associations in Rails?如何在 Rails 中设置条件关联?
【发布时间】:2014-12-28 00:05:15
【问题描述】:

所以我有两个关联的模型用户和杂志。它们通过 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 的用户能够订阅任何杂志。我怎样才能建立这样的条件关联?提前感谢您的帮助!

【问题讨论】:

    标签: ruby-on-rails activerecord associations


    【解决方案1】:

    对于关联,您可以在哈希选项之前传递一个 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

    【讨论】:

    • 糟糕,模型应该被称为Subscription,而不是Registration。感谢您了解这一点。
    猜你喜欢
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-15
    • 2016-07-23
    • 1970-01-01
    相关资源
    最近更新 更多