Если бы мне действительно нужно было запрашивать все отношения пользователя -> курса как одну таблицу, я бы настроил ее следующим образом:
# rails g model assoc user:belongs_to course:belongs_to
class Assoc < ApplicationRecord
enum role: [:student, :teacher, :assistent]
belongs_to :user
belongs_to :course
end
Затем мы хотим настроить сопоставления областей в User иКурс для каждой роли:
has_many :student_assocs, -> { where(role: :student) }
class_name: 'Assoc'
Поскольку мы хотим иметь одинаковые ассоциации в обоих, давайте сохраним их с помощью модуля:
app/models/concerns/associated.rb
# dynamically creates assocations for each role in Assoc.roles enum
module Associated
extend ActiveSupport::Concern
included do
# the plain base assocation
has_many :assocs
# this creates the assocations student_assocs, teacher_assocs, etc
Assoc.roles.keys.each do |role|
# We need to use eval for the second argument as we are creating the lambda dynamically
has_many :"#{role}_assocs", eval( "->{ where(role: #{Assoc.roles[role]})}" ),
class_name: 'Assoc'
end
end
end
Assoc.roles
дает хэшотображения enum, которые мы установили в Assoc.
Затем мы можем включить наш модуль в Course и User и настроить косвенные ассоциации:
class Course < ApplicationRecord
include Associated
has_many :users, through: :assocs
# this creates the assocations students, teachers, etc
Assoc.roles.keys.each do |role|
has_many role.pluralize.to_sym,
through: "#{role}_assocs".to_sym,
source: :user
end
end
class User < ApplicationRecord
include Associated
has_many :courses, through: :assocs
# this creates the assocations courses_as_student, courses_as_teacher, etc
Assoc.roles.keys.each do |role|
has_many "course_as_#{role}".to_sym,
through: "#{role}_assocs".to_sym,
source: :course
end
end