我有两个模型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很新,所以我还在学习。
答案 0 :(得分:231)
您需要以字母顺序添加仅包含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
注意:还有一个自定义表名的选项,可以作为参数传递给名为table_name
的create_join_table。来自docs
默认情况下,连接表的名称来自的联合 前两个参数以字母顺序提供给create_join_table 订购。要自定义表的名称,请提供:table_name 选项:
答案 1 :(得分:29)
这里的答案很陈旧。从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
如果您想对这些列编制索引,请取消注释相应的行,您就可以开始使用了!
答案 2 :(得分:24)
创建连接表时,请特别注意需要在迁移名称/类中以字母顺序列出两个表的要求。如果您的型号名称相似,这可能很容易让您感到困惑,例如: “abc”和“abb”。如果你要跑
rails g migration create_abc_abb_table
您的关系将不按预期工作。你必须使用
rails g migration create_abb_abc_table
代替。
答案 3 :(得分: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