Rails has_and_belongs_to_many 迁移
Posted
技术标签:
【中文标题】Rails has_and_belongs_to_many 迁移【英文标题】:Rails has_and_belongs_to_many migration 【发布时间】:2011-09-27 12:39:51 【问题描述】:我有两个模型 restaurant
和 user
我想执行 has_and_belongs_to_many 关系。
我已经进入模型文件并添加了has_and_belongs_to_many :restaurants
和has_and_belongs_to_many :users
我认为此时我应该能够使用 Rails 3 做类似的事情:
rails generate migration ....
但我尝试过的一切似乎都失败了。我确信这是非常简单的事情,我是 Rails 新手,所以我还在学习。
【问题讨论】:
【参考方案1】:您需要添加一个单独的连接表,其中只有一个restaurant_id
和user_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 排序来了一样。以上是关于Rails has_and_belongs_to_many 迁移的主要内容,如果未能解决你的问题,请参考以下文章
应用程序错误:Heroku,Ruby on Rails 4,警告:rails_12factor,vendor / bundle,no Procfile