Как я могу настроить правильную has_many :через связь с условием или областью действия в таблице объединения

#ruby-on-rails #activerecord #has-many-through

Вопрос:

Рассмотрим 3 модели: Пользователь, Группа и членство в группе

 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
 

Ничего примечательного в пользователе или группе, но у GroupMembership есть два столбца даты и времени, которые определяют, является ли членство текущим: active_at и expire_at. Моя логика заключается в том, что Пользователь является членом группы в данный момент времени, пока active_at <= point_in_time

Я не хочу устанавливать область по умолчанию для GroupMembership, но я бы хотел, чтобы ассоциации has_many включали только текущие объединения.

Я попытался добавить :текущую область (которая определена для членства в группе) в «Принадлежность» в членстве в группе, и я попытался добавить :текущую область в has_many :через группу и пользователя, и каждый подход приводит к ошибкам при попытке найти как группы Пользователей, так и пользователей Группы.

Как мне заставить эти отношения работать так, как задумано?

Отредактировано: Я изначально опустил has_many :group_memberships в своих моделях для этого вопроса, после добавления вопрос почти ответил сам на себя — область, которая существует в модели GroupMembership, относится к has_many :group_memberships моделей пользователей и групп.

Ответ №1:

Не уверен в этом, но вы можете попробовать следующее. В модели пользователя или группы вы можете создать новую функцию для выполнения запроса, а затем просто получить ее. Я не уверен на 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
 

Комментарии:

1. Извините — пожалуйста, посмотрите мои правки и ответьте. Я полагаю, что мой первоначальный вопрос ввел вас в заблуждение. Увидев ваш ответ, я понял как свою ошибку, так и правильный ответ.

Ответ №2:

Добавление области действия в 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