Rails - 建模多个多对多关系

Rails - modeling multiple many to many relationships

我有以下用于创建处理课程的应用程序的用例;

  1. Class 11月1日在Bos由Curt教授A
  2. Class A 于 10 月 19 日在纽约由 Curt 授课
  3. Class 12/5 SF简教A
  4. Class 11月1日Jane在Bos教A

为此应用程序创建具有多对多关系的模型的最佳方法是什么?

应用程序是否应该有一个属于课程、教师和地点的 teachings 模型,其中有一列是日期?

你走在正确的轨道上。以下是我将如何模拟这些关系。假设您有一个 Teacher 模型、一个 Course 模型和一个 TeacherCourses 模型,它们将成为我们教师和课程之间的连接 table:

class Teacher < ActiveRecord::Base
 has_many :courses, through: :teacher_courses
end

class Course < ActiveRecord::Base
 has_many :teachers, through: :teacher_courses
end

class TeacherCourse < ActiveRecord::Base
  belongs_to :course
  belongs_to :teacher
end

您的 teacher_courses table 也将具有位置属性,将记录与相同的 course/teacher 组合区分开来:

create_table :teacher_courses do |t|
  t.integer :teacher_id
  t.integer :course_id
  t.string :location
  t.timestamps
end

你想要的是为每个实体创建一个模型:

  • 课程
  • 老师
  • 位置

然后创建一个连接模型,我选择将其命名为 Lesson:

class Course < ActiveRecord::Base
  has_many :lessons
  has_many :locations, through: :lessons
  has_many :teachers, through: :lessons
end

class Lesson < ActiveRecord::Base
  belongs_to :course
  belongs_to :teacher
  belongs_to :location
end

class Teacher < ActiveRecord::Base
  has_many :lessons
  has_many :courses, through: :lessons
end

class Location < ActiveRecord::Base
  has_many :lessons
  has_many :courses, through: :lessons
  has_many :teachers, through: :lessons
end

I've been playing with this structure for the models but what I noticed is that when submitting the course with a fields_for :locations and a fields_for :instructors, the associations table is creating two separate entries for course_id + instructor_id, course_id + location_id, I would expect a single entry for course_id, instructor_id, location_id. Any thoughts as to why that might happen?

当您隐式创建连接模型时,ActiveRecords 只会跟踪一个关联。要进行三向连接,您需要显式创建连接模型。

<%= form_for(@course) do |f| %>

  <div class="field>
    <% f.label :name %>
    <% f.text_field :name %>
  </div>

  <fieldset>
    <legend>Lesson plan<legend>
    <%= f.fields_for(:lessons) do |l| %>
      <div class="field>
         <% l.label :name %>
         <% l.text_field :name %>
      </div>
      <div class="field">
         <% l.label :starts_at %>
         <% l.datetime_select :starts_at %>
      </div>
      <div class="field">
         <% l.label :teacher_ids %>
         <% l.collection_select :teacher_ids, Teacher.all, :id, :name, multiple: true %>
      </div>
      <div class="field">
         <% l.label :location_id %>
         <% l.collection_select :location_id, Location.all, :id, :name %>
      </div>
    <% end %>
  </fieldset>
<% end %>

fields_foraccepts_nested_attributes 是强大的工具。然而,传递向下嵌套多个级别的属性可以被视为某种反模式,因为它创造了上帝 类 和意想不到的复杂性。

更好的替代方法是使用 AJAX 发送单独的请求来创建教师和位置。它提供了更好的用户体验、更少的验证难题和更好的应用程序设计。