【问题标题】:Rails has_and_belongs_to_many migrationRails has_and_belongs_to_many 迁移
【发布时间】:2011-09-27 12:39:51
【问题描述】:

我有两个模型 restaurantuser 我想执行 has_and_belongs_to_many 关系。

我已经进入模型文件并添加了has_and_belongs_to_many :restaurantshas_and_belongs_to_many :users

我认为此时我应该能够使用 Rails 3 做类似的事情:

rails generate migration ....

但我尝试过的一切似乎都失败了。我确信这是非常简单的事情,我是 Rails 新手,所以我还在学习。

【问题讨论】:

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


    【解决方案1】:

    您需要添加一个单独的连接表,其中只有一个restaurant_iduser_id(无主键),按字母顺序

    首先运行您的迁移,然后编辑生成的迁移文件。

    Rails 3

    rails g migration create_restaurants_users_table
    

    Rails 4

    rails g migration create_restaurants_users
    

    Rails 5

    rails g migration CreateJoinTableRestaurantUser restaurants users
    

    来自docs

    还有一个生成器,如果 JoinTable 会生成连接表 是名称的一部分:


    您的迁移文件(注意 :id => false;这是阻止创建主键的原因):

    Rails 3

    class CreateRestaurantsUsers < ActiveRecord::Migration
      def self.up
        create_table :restaurants_users, :id => false do |t|
            t.references :restaurant
            t.references :user
        end
        add_index :restaurants_users, [:restaurant_id, :user_id]
        add_index :restaurants_users, :user_id
      end
    
      def self.down
        drop_table :restaurants_users
      end
    end
    

    Rails 4

    class CreateRestaurantsUsers < ActiveRecord::Migration
      def change
        create_table :restaurants_users, id: false do |t|
          t.belongs_to :restaurant
          t.belongs_to :user
        end
      end
    end
    

    t.belongs_to 将自动创建必要的索引。 def change 将自动检测向前或回滚迁移,无需向上/向下。

    Rails 5

    create_join_table :restaurants, :users do |t|
      t.index [:restaurant_id, :user_id]
    end
    

    注意:还有一个自定义表名选项,可以作为参数传递给 create_join_table,名为 table_name。来自docs

    默认情况下,连接表的名称来自 提供给 create_join_table 的前两个参数,按字母顺序排列 命令。要自定义表的名称,请提供 :table_name 选项:

    【讨论】:

    • @Dex - 出于好奇,您能否解释一下为什么要使用第二个复合索引,用反向列顺序定义?我的印象是列顺序无关紧要。我不是DBA,只是想进一步了解自己。谢谢!
    • @Jimbo 你不需要那样,它真的取决于你的查询。索引从左到右读取,因此如果您在 restaurant_id 上搜索,第一个索引将是最快的。如果您在 user_id 上搜索,第二个会有所帮助。如果您同时搜索两者,我认为数据库足够智能,只需要一个。所以我想第二个真的不需要复合。这只是一个例子。这是一个 Rails 问题,所以在 DB 部分发布会产生更完整的答案。
    • 第二个索引有一些冗余 - 只要您同时查询 restaurant_id 和 user_id,它们在 SQL 中的顺序无关紧要,将使用第一个索引。如果您只查询 restaurant_id,也将使用它。第二个索引只需要在 :user_id 上,并且会在您只查询 user_id 的情况下使用(由于其键的顺序,第一个索引无济于事)。
    • 在 Rails 4 中,迁移必须是 rails g migration create_restaurants_users,最后没有 table
    • 您也可以使用 rails g migration CreateJoinTableRestaurantUser 餐厅用户。阅读guides.rubyonrails.org/migrations.html#creating-a-join-table
    【解决方案2】:

    这里的答案已经过时了。从 Rails 4.0.2 开始,您的迁移使用 create_join_table

    要创建迁移,请运行:

    rails g migration CreateJoinTableRestaurantsUsers restaurant user
    

    这将生成以下内容:

    class CreateJoinTableRestaurantsUsers < ActiveRecord::Migration
      def change
        create_join_table :restaurants, :users do |t|
          # t.index [:restaurant_id, :user_id]
          # t.index [:user_id, :restaurant_id]
        end
      end
    end
    

    如果您想索引这些列,请取消注释相应的行,一切顺利!

    【讨论】:

    • 我通常会取消注释其中一个索引行并将unique: true 添加到其中。这将防止创建重复的关系。
    【解决方案3】:

    对于 HABTM 关系,您需要创建一个连接表。只有连接表,该表不应有 id 列。试试这个迁移。

    def self.up
      create_table :restaurants_users, :id => false do |t|
        t.integer :restaurant_id
        t.integer :user_id
      end
    end
    
    def self.down
      drop_table :restaurants_users
    end
    

    你必须检查this relationship rails guide tutorials

    【讨论】:

    • 我认为您不需要模型,并且我在链接中没有看到任何关于需要模型来建立 HABTM 关系的内容。
    • 要加快生成查询的速度,请在 id 字段中添加索引。
    【解决方案4】:

    在创建连接表时,请注意迁移名称/类中两个表需要按字母顺序列出的要求。如果您的型号名称相似,这很容易咬到您,例如“abc”和“abb”。如果你要跑步

    rails g migration create_abc_abb_table
    

    您的关系将不会按预期工作。你必须使用

    rails g migration create_abb_abc_table
    

    改为。

    【讨论】:

    • 哪个先出现? foo 还是 foo_bar?
    • 在 Rails 控制台中运行:["foo_bar", "foo", "foo bar"].sort # => ["foo", "foo bar", "foo_bar"] Unix 排序来了一样。
    猜你喜欢
    • 2020-10-28
    • 2014-02-28
    • 2011-05-21
    • 2016-05-28
    • 1970-01-01
    • 2011-12-02
    • 2012-01-14
    • 1970-01-01
    • 2010-10-16
    相关资源
    最近更新 更多