【问题标题】:Rails migration for has_and_belongs_to_many join tablehas_and_belongs_to_many 连接表的 Rails 迁移
【发布时间】:2011-05-21 20:04:53
【问题描述】:

如何使用script/generate migrationhas_and_belongs_to_many 关系创建连接表?

应用程序在 Rails 2.3.2 上运行,但我也安装了 Rails 3.0.3。

【问题讨论】:

    标签: ruby-on-rails migration code-generation has-and-belongs-to-many


    【解决方案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 置于与创建表的迁移相同的迁移中,则将失败。
    【解决方案2】:

    在rails 4中,你可以简单地使用

    create_join_table :table1s, :table2s

    就是这样。

    注意:表 1、表 2 必须包含字母数字。

    【讨论】:

    • 这是一个很好的最新解决方案。请注意,连接表不能作为模型访问,而是通过在两个连接表上设置的 has_and_belongs_to_many 关系访问。
    【解决方案3】:

    地点:

    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
    

    用于导轨

    script/generate migration students_teachers student_id:integer teacher_id:integer
    

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

    然后仅对于 rails 3 及以下版本,您需要编辑生成的迁移,以便不创建 id 字段:

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

    【讨论】:

    • 这是唯一真正回答问题的回复。
    • @pingu:除了它不起作用,至少在 Rails 3.2 中。生成的迁移文件为空白。
    • @hoffmanc 如果不指定任何字段,它将生成一个空的迁移文件。如果您希望 Rails 自动将它们添加到迁移文件中,则必须指定这些字段。
    • 你好,我正在尝试rails generate migration CreateJoinTableTeacherStudent teacher student 而不是rails generate migration CreateJoinTableStudentTeacher student teacher,是一样的吗? S(tudent) 需要在 T(eacher) 之前吗?
    • @zx1986,是的,它需要按这个顺序。
    【解决方案4】:

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

    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)
    

    我确实发现这个基于“什么医生”的答案很有用,而且讨论当然也很有用。

    【讨论】:

      【解决方案5】:

      has_and_belongs_to_many 表必须与此格式匹配。我假设has_and_belongs_to_many 加入的两个模型已经在数据库中: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 =&gt; true,那么您应该(在rails3 中)将:uniq =&gt; true 传递给has_and_belongs_to_many

      更多信息:Rails Docs

      2010-12-13 更新我已经更新它以删除 id 和时间戳...基本上MattDiPasqualenunopolonia 是正确的:不能有 id,必须有不是时间戳,否则 Rails 将不允许 has_and_belongs_to_many 工作。

      【讨论】:

      • 实际上,一个连接表应该只有两个引用列,并且没有id或时间戳列。这是您提供的链接中has_and_belongs_to_many migration 的更好示例。我正在寻找一种方法来从命令行使用script/generate migration ...
      • 嗯,它不必有时间戳;我在示例中将其标记为可选。不过,我建议添加 id。在某些情况下,ID 或时间戳都可能有用。但我强烈推荐这个 ID。
      • 好的。什么情况下 ID 会有用?
      • 一个例子是关系是否重要到足以拥有一个观点。它还可以用于通过传递relationship.id 来加速访问数据库,而不是重复查找它。它还使对数据库的故障排除变得更加容易。特别是如果其他列的 id 非常高。记住 id:12345 而不是 id:54321-id:67890 更容易——但话虽如此,如果表变得非常大,那么您可能希望能够通过不为每个关系分配另一个 id 来节省空间。跨度>
      • 我不认为多列索引是解决这个问题的正确方法。它适用于查询特定苹果以找到相关的橙子,但反之则不行。两个单列索引将允许有效地查询两个方向,可能会对特定苹果、橙子组合的存在性检查造成很小的损失。
      【解决方案6】:

      您应该按字母顺序将表命名为要连接的 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

      【讨论】:

        猜你喜欢
        • 2011-09-27
        • 2020-10-28
        • 2014-02-28
        • 2011-12-02
        • 2016-05-28
        • 2010-10-21
        • 1970-01-01
        • 1970-01-01
        • 2011-09-02
        相关资源
        最近更新 更多