Rails has_and_belongs_to_many迁移

dbs*_*one 114 migration ruby-on-rails has-and-belongs-to-many ruby-on-rails-3

我有两个模型restaurantuser我要执行has_and_belongs_to_many关系.

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

我假设在这一点上我应该能够像Rails 3那样做:

rails generate migration ....
Run Code Online (Sandbox Code Playgroud)

但我所尝试的一切似乎都失败了.我确信这是非常简单的我对rails很新,所以我还在学习.

Dex*_*Dex 249

您需要按字母顺序添加一个仅包含a restaurant_iduser_id(无主键)的单独连接表.

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

Rails 3

rails g migration create_restaurants_users_table
Run Code Online (Sandbox Code Playgroud)

导轨4:

rails g migration create_restaurants_users
Run Code Online (Sandbox Code Playgroud)

Rails 5

rails g migration CreateJoinTableRestaurantUser restaurants users
Run Code Online (Sandbox Code Playgroud)

来自文档:

如果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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

Rails 5

create_join_table :restaurants, :users do |t|
  t.index [:restaurant_id, :user_id]
end
Run Code Online (Sandbox Code Playgroud)

注意:还有一个自定义表名称的选项,可以作为参数传递给create_join_table调用table_name.来自文档

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

  • 在rails 4中,迁移必须是`rails g migration create_restaurants_users`,最后没有_table_. (13认同)
  • @Jimbo你不需要这样,它真的取决于你的查询.索引从左向右读取,因此如果您在"restaurant_id"上搜索,第一个索引将是最快的.如果你在`user_id`上搜索,第二个将有所帮助.如果你在两者上搜索,我认为数据库足够聪明,只需要一个.所以我猜第二个并不需要复合.这更像是一个例子.这是一个Rails问题,因此在数据库部分发布将产生更完整的答案. (9认同)
  • @Dex - 出于好奇,你能解释为什么你要使用第二个复合索引,用反向列顺序定义吗?我的印象是列顺序无关紧要.我不是DBA,只想进一步了解自己.谢谢! (6认同)
  • 您还可以使用rails g migration CreateJoinTableRestaurantUser餐厅用户.阅读http://guides.rubyonrails.org/migrations.html#creating-a-join-table (5认同)
  • 第二个索引有一些冗余 - 只要您在restaurant_id和user_id上查询,它们在SQL中的顺序无关紧要,并且将使用第一个索引.如果您只在restaurant_id上查询,也会使用它.第二个索引只需要打开:user_id,并且会在你只查询user_id的情况下使用(第一个索引由于其键的顺序而无法帮助). (3认同)
  • 值得注意的是,`create_join_table` 至少可以在 Rails &gt;= 4.2 中使用 (2认同)

Jan*_*imo 30

这里的答案很陈旧.从Rails 4.0.2开始,您的迁移就可以使用了create_join_table.

要创建迁移,请运行:

rails g migration CreateJoinTableRestaurantsUsers restaurant user
Run Code Online (Sandbox Code Playgroud)

这将生成以下内容:

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
Run Code Online (Sandbox Code Playgroud)

如果你想索引这些列,取消注释相应的行,你就可以了!

  • 我通常会取消对索引行之一的注释并为其添加“unique: true”。这将防止创建重复的关系。 (4认同)

sha*_*ker 24

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

rails g migration create_abc_abb_table
Run Code Online (Sandbox Code Playgroud)

你的关系不会按预期工作.你必须使用

rails g migration create_abb_abc_table
Run Code Online (Sandbox Code Playgroud)

代替.


Moh*_*ain 6

对于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
Run Code Online (Sandbox Code Playgroud)

您必须检查此关系rails指南教程