Многоцелевой has_many через: - PullRequest
0 голосов
/ 12 октября 2018

У меня есть три модели:

User(name: string)
Course(name: string)
Assoc(user_id: integer, ta_id: integer, teach_id: integer, student_id: integer)

Я хочу иметь возможность ассоциировать пользователя с курсом, например, преподавателя или студента.Я не уверен, что это соответствует полиморфной идее в ActiveRecord.Вот что у меня есть, но это не совсем работает:

class User < ApplicationRecord
  has_many :tas, class_name: "Assoc", foreign_key: :ta_id
  has_many :teaches, class_name: "Assoc", foreign_key: :teach_id
  has_many :takes, class_name: "Assoc", foreign_key: :student_id

  has_many :ta_courses, through: :tas
  has_many :taken_courses, through: :tas
  has_many :taught_courses, through: :tas
end

Это не работает:

irb(main):056:0> User.find(1).ta_courses
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
Traceback (most recent call last):
        1: from (irb):56
ActiveRecord::HasManyThroughSourceAssociationNotFoundError (Could not find the source association(s) "ta_course" or :ta_courses in model Assoc. Try 'has_many :ta_courses, :through => :tas, :source => <name>'. Is it one of ?)
irb(main):057:0>

Любые указатели приветствуются!

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Если бы мне действительно нужно было запрашивать все отношения пользователя -> курса как одну таблицу, я бы настроил ее следующим образом:

# 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
0 голосов
/ 12 октября 2018

Похоже, вы не построили отношения от модели Assoc к модели курса.Ваша модель Assoc должна иметь course_id, чтобы она выглядела следующим образом:

Assoc(user_id: integer, ta_id: integer, teach_id: integer, student_id: integer, course_id: integer)

Тогда вам понадобится отношение принадлежать к модели Assoc:

class Assoc < ApplicationRecord
  belongs_to :course
end

Наконец, ваше has_many через отношения вПользовательская модель построена неправильно (все через тас).Ваше сообщение об ошибке дает вам подсказку относительно последней вещи, которую вам нужно сделать, а именно определить псевдоним отношений с помощью источника:

class User < ApplicationRecord
  has_many :tas, class_name: "Assoc", foreign_key: :ta_id
  has_many :teaches, class_name: "Assoc", foreign_key: :teach_id
  has_many :takes, class_name: "Assoc", foreign_key: :student_id

  has_many :ta_courses, through: :tas, source: :course
  has_many :taught_courses, through: :teaches, source: :course
  has_many :taken_courses, through: :takes, source: :course
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...