我如何设置适当的 has_many :through 与连接 table 上的条件或范围的关系

How can I set up a proper has_many :through relationship with a condition, or scope, on the join table

考虑 3 个模型,User、Group 和 GroupMembership

class User < ApplicationRecord
  has_many :group_memberships
  has_many :groups, through: :group_memberships
end

class Group < ApplicationRecord
  has_many :group_memberships
  has_many :users, through: :group_memberships
end

class GroupMembership < ApplicationRecord
  belongs_to :user
  belongs_to :group
  
  scope :current, -> { where(active_at: [nil, (..Time.current)], expires_at: [nil, (Time.current..)]) }
end

User 或 Group 没有什么特别之处,但是 GroupMembership 有两个 DateTime 列来控制成员资格是否是最新的:active_at 和 expires_at。我的逻辑是,只要 active_at <= point_in_time < expires_at(nils 也可以),用户在给定时间点就是组的成员。

我不想在 GroupMembership 上设置默认范围,但我希望 has_many 关联仅包含当前的联接。

我尝试将 :current 范围(为 GroupMembership 定义)添加到组成员身份中的 belongs_to,并且我尝试将 :current 范围添加到 has_many :through组和用户以及每种方法在尝试查找用户的组和组的用户时都会导致错误。

如何让这些关系按预期工作?

已编辑:我最初在我的模型中省略了这个问题的 has_many :group_memberships,添加后,问题几乎自己回答了 - 范围存在于 GroupMembership 模型中,属于 User 和 Group 模型的 has_many :group_memberships。

不确定,但您可以尝试以下操作。在用户或组模型中,您可以创建一个新函数来执行查询,然后只检索它。我不是 100% 确定语法,但它是这样的:

class User < ApplicationRecord
    has_many :group_memberships
    has_many :groups, through: :group_memberships

    def self.current
      self.joins(:group_memberships).where(active_at: [nil, (..Time.current)], expires_at: [nil, (Time.current..)])
    end
end

然后在你的控制器中你可以做:

User.current

将范围添加到 has_many :group_memberships 在用户和组模型中完全符合要求。

class User < ApplicationRecord
  has_many :group_memberships, -> { current }
  has_many :groups, through: :group_memberships
end

class Group < ApplicationRecord
  has_many :group_memberships, -> { current }
  has_many :users, through: :group_memberships
end