Подтвердить что ты не робот

В Ruby on Rails, как я могу создать область для отношений has_many?

Вот пример:

Пусть говорит, что у меня есть объект Student, который имеет has_many отношения с объектами ReportCard. Объекты ReportCard имеют логическое поле, называемое "градуированным", эти флаги, которые они были оценены. Так выглядит:

class Student < ActiveRecord
  has_many :report_cards
end

class ReportCard < ActiveRecord
  # graded :boolean (comes from DB)
  belongs_to :student
end

Теперь предположим, что вы хотите создать область по умолчанию, чтобы, если у ученика нет градуированных ReportCards, вы хотите увидеть все из них, но если у них есть хотя бы одна градуированная ReportCard, вы хотите видеть только градуированные, Наконец, скажем, вы заказываете их с помощью "semester_number".

Использование этой области в ReportCard работает правильно:

scope :only_graded_if_possible, ->(student) { where(graded: true, student: student).order(:semester_number).presence || order(:semester_number) }

Но я хочу, чтобы это была область по умолчанию для Student, поэтому я попытался:

class Student < ActiveRecord
  has_many :report_cards, ->{ where(graded: true).order(:semester_number).presence || order(:semester_number) }
end

но это не работает. Он не будет возвращать никакие report_cards, если в целом db есть одна градуированная отчетная карточка. Рассматривая запущенные запросы, сначала он запускает что-то вроде:

SELECT report_cards.* FROM report_cards WHERE reports_cards.graded = t ORDER BY semester_number ASC

Я думаю, что это должно быть настоящее? проверьте часть запроса на присутствие и обратите внимание, что он не фильтрует на Студент вообще! Поэтому, если есть одна масштабируемая версия report_card, проверка проходит, а затем выполняется следующий запрос, чтобы получить возвращаемое значение:

SELECT report_cards.* FROM reports_card WHERE report_card.student_id = 'student id here' AND report_card.graded = t ORDER BY semester_number

Этот запрос действительно был бы правильным, если бы у ученика была оцененная карта отчета, но она всегда пуста, если он этого не делает.

Я предполагаю, что после этого добавляется фильтрация на Student. Поэтому я попытался как-то заставить его отфильтровать ученика с места в карьер:

has_many :report_cards, ->{ where(graded: true, student: self).order(:semester_number).presence || order(:semester_number) }

Это не работает либо потому, что кажется, что "я" в этой области не является объектом Student, как я предполагал, но является списком всех идентификаторов report_card. Ниже приведен запрос:

SELECT report_cards.* FROM report_cards WHERE report_cards.graded = t AND report_cards.student_id IN (SELECT report_cards.id FROM report_cards) ORDER BY semester_number ASC

Это даже близко не подходит. Как я могу заставить это работать?

Я думаю, что это действительно сводится к тому, что кто-то может передать "я" (что означает текущий объект Student) в качестве параметра в область, применяемую в "has_many". Возможно, это невозможно.

4b9b3361

Ответ 1

Вы можете передать объект в область has_many как параметр для лямбда

has_many :report_cards, -> (student) { ... }

Ответ 2

Попробуйте следующее:

class Student < ActiveRecord::Base
  has_many :report_cards, ->{ where(graded: true).order(:semester_number).presence || unscoped.order(:semester_number) }
end

Ответ 3

Я использую это в своем проекте, где у меня есть модель, связанная с пользователями:

has_many :users, -> { only_deleted }

И в модели Users создайте область only_deleted, возвращая ваши удаленные пользователи.