has_and_belongs_to_many连接表的Rails迁移


Answers:


228

哪里:

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :students
end

class Student < ActiveRecord::Base
  has_and_belongs_to_many :teachers
end

对于导轨4:

rails generate migration CreateJoinTableStudentTeacher student teacher

对于导轨3:

rails generate migration students_teachers student_id:integer teacher_id:integer

用于<3的导轨

script/generate migration students_teachers student_id:integer teacher_id:integer

(请注意,表名按字母顺序列出了两个连接表)

然后仅对于Rails 3和更低版本,您需要编辑生成的迁移,因此不会创建id字段:

create_table :students_teachers, :id => false do |t|

16
这是实际回答问题的唯一答复。
pingu 2012年

8
@pingu:至少在Rails 3.2中不起作用。生成的迁移文件为空。
hoffmanc

7
作品为Rails 4
费利佩番

2
@hoffmanc如果您不指定任何字段,它将生成一个空的迁移文件。如果希望Rails将其自动添加到迁移文件中,则必须指定字段。
安德鲁(Andrew)

1
您好,我正在尝试rails generate migration CreateJoinTableTeacherStudent teacher student而不是rails generate migration CreateJoinTableStudentTeacher student teacher,是否一样?S(学生)需要在T(每个)之前吗?
zx1986

138

一个has_and_belongs_to_many表必须格式相匹配。我假定这两个模型由被连接has_and_belongs_to_many已经在DB:applesoranges

create_table :apples_oranges, :id => false do |t|
  t.references :apple, :null => false
  t.references :orange, :null => false
end

# Adding the index can massively speed up join tables. Don't use the
# unique if you allow duplicates.
add_index(:apples_oranges, [:apple_id, :orange_id], :unique => true)

如果:unique => true在索引上使用,则应该(在rails3中)传递:uniq => truehas_and_belongs_to_many

更多信息:Rails Docs

更新2010-12-13我已经对其进行了更新,以删除ID和时间戳...基本上MattDiPasqualenunopolonia正确的是:不能有ID,也不能有时间戳,否则Rails将无法has_and_belongs_to_many工作。


6
实际上,联接表应该仅具有两个引用列,而没有id或timestamp列。这是从您提供的链接进行has_and_belongs_to_many迁移的更好示例。我正在寻找一种从命令行使用script/generate migration...
ma11hew28

好吧,它没有时间戳记。我在示例中将其标记为可选。不过,我建议您添加ID。在某些情况下,ID或时间戳都可能有用。但我强烈建议您使用ID。
docwhat 2010年

好。ID在什么情况下有用?
ma11hew28 2010年

一个例子是,这种关系是否足够重要以至于可以查看。它也可以通过传递relationship.id来加快访问数据库的速度,而不必反复查找它。它还使对数据库进行故障排除更加容易。特别是如果其他列的ID确实很高。更容易记住id:12345而不是id:54321-id:67890-但是,如果表很大,那么您可能希望通过不为每个关系分配另一个id来节省空间。
docwhat 2011年

2
我认为多列索引不是解决此问题的正确方法。它可以查询特定的苹果,以找到相关的橙子,反之则不行。两个单列索引将允许有效地查询两个方向,而对特定苹果,橙色组合的存在性检查可能会损失很小。
约瑟夫·罗德

14

您应按字母顺序为表命名要连接的2个模型的名称,并将两个模型ID放在表中。然后将每个模型彼此连接,在模型中创建关联。

这是一个例子:

# in migration
def self.up
  create_table 'categories_products', :id => false do |t|
    t.column :category_id, :integer
    t.column :product_id, :integer
  end
end

# models/product.rb
has_and_belongs_to_many :categories

# models/category.rb
has_and_belongs_to_many :products

但这不是很灵活,您应该考虑使用has_many:through


6

最佳答案显示了一个复合索引,我认为该索引不会用于从橘子中查找苹果。

create_table :apples_oranges, :id => false do |t|
  t.references :apple, :null => false
  t.references :orange, :null => false
end

# Adding the index can massively speed up join tables.
# This enforces uniqueness and speeds up apple->oranges lookups.
add_index(:apples_oranges, [:apple_id, :orange_id], :unique => true)
# This speeds up orange->apple lookups
add_index(:apples_oranges, :orange_id)

我确实发现基于“ What Doctor”的答案很有用,而且讨论当然也是如此。


4

在rails 4中,您可以轻松使用

create_join_table:table1s,:table2s

这是全部。

注意:您必须禁止使用字母数字的table1,table2。


这是一个很好的最新解决方案。注意,联接表不能作为模型访问,而是可以通过在两个联接表上设置的has_and_belongs_to_many关系来访问。
Taylored网站

1

我喜欢这样做:

rails g migration CreateJoinedTable model1:references model2:references。这样,我将获得如下所示的迁移:

class CreateJoinedTable < ActiveRecord::Migration
  def change
    create_table :joined_tables do |t|
      t.references :trip, index: true
      t.references :category, index: true
    end
    add_foreign_key :joined_tables, :trips
    add_foreign_key :joined_tables, :categories
  end
end

我喜欢在这些列上建立索引,因为我经常会使用这些列进行查找。


add_foreign_key如果放置在与创建表相同的迁移中,将失败。
阿迪布·萨德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.