Rails - 建立多对多关系

问题描述:

我有以下用例来创建处理课程的应用程序;通过简略的教导Rails - 建立多对多关系

  1. 类A由简略教导的Bos上11/1
  2. A类中NY上10/19
  3. 类A由简SF讲授12/5
  4. A类是由简博斯教授在11/1

什么是与许多为这个应用程序一对多关系创建模型的最佳方式?

应该有teachings模型属于课程,教师和地点与日期列?

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

  • 课程
  • 教师
  • 位置

然后创建我已经选择调用课各种各样的加盟模式:

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 

我一直在玩这个结构模型,但我注意到的是,当提交与fields_for :位置和fields_for:教练的课程时,关联表为 为course_id + instructor_id创建两个单独的条目,course_id + location_id,我期望为course_id,instructor_id,location_id指定一个条目。任何想法为什么可能发生?

当您隐式创建连接模型时,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发送单独的请求来创建教师和位置。它提供了更好的用户体验,更少的验证问题和更好的应用程序设计。

+0

感谢这一点 - 我一直在玩这个模型的结构,但我注意到当用'fields_for:locations'和'fields_for:instructors'提交课程时,'associations'表创建了两个独立的course_id + instructor_id,course_id + location_id的条目,我期望course_id,instructor_id,location_id的单个条目。任何想法为什么可能发生? –

+0

因为你做错了。当连接模型不仅仅是一个双向连接模型时,你不能隐式创建它,因为ActiveRecord只能追踪一个关系。看我的编辑。 – max

+0

感谢您的信息,我不知道Rails有三种方式连接的限制。所以要做到这一点的唯一方法是分别创建位置和老师,然后使用集合选择来关联它们? –

您正处于正确的轨道上。以下是我将如何建模这些关系。比方说,你有一个Teacher模型,Course模型和TeacherCourses模型,这将是我们参加的教师和课程之间表:

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表也有位置属性区分来自同一课程/教师记录组合:

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

我仍然会使用一个单独的表来进行数据规范化。 – max

+0

不知道我在追随。这将如何有益?我相信你是对的,只是对权衡 – Cyzanfar

+1

好奇而已,而不是在D-Wing,Derpville,Derpville,DERPLAND大学的不同变体的字符串上徘徊,你指向一个标准化记录。这也使得它可以直接添加地理位置等功能。 – max