Ruby on Rails - 引用many_to_many关系

时间:2013-12-20 09:16:05

标签: ruby-on-rails ruby

因此,如果我有一个只有ids的many_to_many表,并且我想在另一个模型中引用它,我该怎么做?

所以在名为Rating的模型中,我想说它与关联中的这两个东西相关联,在本例中是Course和Textbook。因此,评级由教科书和课程定义。我应该将两个id属性添加到与两者相关联的评级吗?我应该在many_to_many中添加一个ID,然后在Rating表中有一个ID属性吗?或者我还能做些什么吗?

更新

所以这是我的ERD到目前为止。您可以忽略学生和教授的事情。 ERD 在右侧,我根据@RichPeck制作的桌子。我对如何创建条目感到困惑。让我们说例如我创建了一个课程。

course = Course.new(params)

然后我这样做了一本教科书。

textbook = course.textbooks.build(params)

现在当我course.textbooks时,它会列出我刚刚制作的教科书,但当我textbook.courses时,我会得到一个空列表。此外,在保存它们并退出shell然后重新打开之后,两个命令都会重新输入空列表。现在这是因为连接表CourseTextboks是空的。为什么rails没有添加条目?我需要做一些特别的事吗?

以下是相关文件:

CreateCourseTextbooksMigration

class CreateCourseTextbooks < ActiveRecord::Migration
  def change
    create_table :course_textbooks do |t|
      t.references :course, index: true
      t.references :textbook, index: true

      t.timestamps
    end
  end
end

CreateTextbookMigration

class CreateTextbooks < ActiveRecord::Migration
  def change
    create_table :textbooks do |t|
      t.string :title
      t.string :authors
      t.string :edition
      t.float :price
      t.string :isbn
      t.text :description
      t.string :image_url
      t.date :published

      t.timestamps
    end
  end
end

CreateCourseMigration

class CreateCourses < ActiveRecord::Migration
  def change
    create_table :courses do |t|
      t.string :title
      t.string :letters
      t.integer :number

      t.timestamps
    end
  end
end

模特:

class Course < ActiveRecord::Base
  has_many :student_courses
  has_many :students, through: :student_courses

  has_many :professor_courses
  has_many :professors, through: :professor_courses

  has_many :textbook_courses
  has_many :textbooks, through: :textbook_courses

  validates_presence_of :title, :letters, :number
end

教科书

class Textbook < ActiveRecord::Base
  has_many :textbook_courses
  has_many :courses, through: :textbook_courses
end

CourseTextbook

class CourseTextbook < ActiveRecord::Base
  belongs_to :course
  belongs_to :textbook

  has_many :rating_course_textbooks, :class_name => "RatingCourseTextbook" 
  has_many :ratings, :through => :rating_course_textbooks

  validates_presence_of :course
end

你能帮助我吗,伙计们?

UPDATE2:

经过大约半小时的搜索并且更多地关注创建对象时生成的SQL,我发现了它。所以当你执行course.build它只返回对象并以某种方式链接它,但不是通过加入表。我发现你必须保存课程而不是新教授,或者只使用创建。

这就是发生的事情

>>> course = Course.create(params)
    # INSERT into courses table
>>> professor = course.build(params)

>>> professor.save
    # INSERT into professors table
>>> course.professors
    # [Professor {id:1, blah}]
>>> professor.courses
    # []

这就是现在有效的方法

>>> course = Course.create(params)
    # INSERT into courses table
>>> professor = course.build(params)

>>> course.save
    # INSERT into professors table
    # INSERT into professor_courses table
>>> course.professors
    # [Professor {id:1, blah}]
>>> professor.courses
    # [Course {id:1, blah}]

YAY!现在只是看看它是否适用于我的其他模型,如RatingsCourseTextbooks

UPDATE3 所以在搞了一会儿之后,我发现我让它变得太复杂了。评级只能有一个CourseTextbook,所以我不需要另一个连接表。我刚刚将一个CourseTextbook ID添加到评级。

New ERD

感谢您的支持

2 个答案:

答案 0 :(得分:2)

我猜你是Rails的新手,所以我会在这里解释一下这对你有用:


<强> ActiveRecord Associations

Rails的核心功能之一是ActiveRecord关联

ActiveRecord使关系数据库架构生动,允许您从单个查询引用不同的“相关”模型。这是你如何调用@user.images

ActiveRecord位于数据库层之上,并且您的模型使用has_manybelongs_to等参考引用。如果您想引用相关模型,则必须使用这些模型,如下所示:

#app/models/user.rb
Class User < ActiveRecord::Base
    has_many :images
end 

#app/models/image.rb
Class Image < ActiveRecord::Base
    belongs_to :user
end

您的代码

似乎您正在使用has-and-belongs-to-many

如Sachin Singh所述,你可能最好使用polymorphic relationship这些模型: Polymorphic Association

这允许您从多个模型引用关系,Rails / ActiveRecord使用模型名称&amp ;;填充多态字段。 ID。以下是您的模型的外观:

Class Rating < ActiveRecord::Base
    belongs_to :rateable, :polymorphic => true
end

Class Course < ActiveRecord::Base
    has_many :ratings, :as => :rateable
end

Class Textbook < ActiveRecord::Base
   has_many :ratings, :as => :rateable
end

<强>更新

如果您想要为某些课程制作特定教科书并对这些教科书进行评分,您最好使用has_many :through

这可能完全不合适,但我将coursestextbooks表设置为“顶级”表,然后将textbook_courses作为连接 - 模型。然后,我将textbook_course_ratings作为另一个连接模型,以便为每本教科书提供所需的评分

目标是@course.textbooks.ratings

Class Course < ActiveRecord::Base
    has_many :textbook_courses
    has_many :textbooks, :through => :textbook_courses
end

Class Textbook < ActiveRecord::Base
   has_many :textbook_courses
   has_many :courses, :through :textbook_courses
end

Class TextbookCourse < ActiveRecord::Base
   belongs_to :textbook
   belongs_to :course

   has_many :textbook_course_ratings, :class_name => "TextbookCourseRating" 
   has_many :ratings, :through => :textbook_course_ratings
end

Class TextbookCourseRating < ActiveRecord::Base
    belongs_to :textbook_course
    belongs_to :rating
end

Class Rating < ActiveRecord::Base
    has_many :textbook_course_ratings, :class_name => "TextbookCourseRating"
    has_many :textbooks, :through => :textbook_ratings
end

我之前从未做过这么深的has_many :through关系;但它应该工作

有几点需要注意:

  1. 您必须更改您的联接表以包含primary key(ID) - HABTM不需要它们,但HMT会
  2. 你将有很多accepts_nested_attributes_for要做:)
  3. 您的联接表格如下:

    textbook_courses
    id | course_id | textbook_id | created_at | updated_at
    
    textbook_courses_ratings
    id | textbook_course_id | rating_id | created_at | updated_at
    

答案 1 :(得分:0)

如果,课程和TextBook有很多评级,那么评级表应该是多态的。

class Rating < AcrtiveRecord::Base    
  belongs_to :ratable, polymorphic: true    
end

class Course < ActiveRecord::Base
  has_many :ratings, as: :ratable
end

class TextBook < ActiveRecord::Base
  has_many :ratings, as: :ratable
end

评级表将有两列名为ratable_type和ratable_id

ratable_type:它将包含课程名称课程或课本。

ratable_id:它将保存相关abject的id。