我们在两个模型之间有一个简单的 has_and_belongs_to_many 关系。我们想在该模型中添加一些参数,因此我们需要将其更改为 has_many :through 类型的模型。
据我所知,我们需要添加一个 id 列(以及我们想要的任何列)。但是,我并不清楚 100% 如何做到这一点。如果我们添加一个整数列 :id,rails 会知道那是 'id' 主键吗?
我们使用的是最新的 3.x。
我们在两个模型之间有一个简单的 has_and_belongs_to_many 关系。我们想在该模型中添加一些参数,因此我们需要将其更改为 has_many :through 类型的模型。
据我所知,我们需要添加一个 id 列(以及我们想要的任何列)。但是,我并不清楚 100% 如何做到这一点。如果我们添加一个整数列 :id,rails 会知道那是 'id' 主键吗?
我们使用的是最新的 3.x。
假设您的数据库表为由 rails 创建的许多 has_and_belong_to 是patients_physicians
您需要做的就是生成这样的模型
rails g model patients_physician --skip-migration
然后您可以使用迁移命令添加所需的任何列,例如 do
rails g migration add_new_column_to_patients_physician new_column
并且您的数据仍然完好无损,您可以根据您生成的模型进行查询。
不要忘记添加
belongs_to :model_1
belongs_to :model_2
到新添加的模型 patients_physician
那么您将可以在您需要的模型中进行操作。
has_many patients_physician
has_many :model_2, through: :patients_physician
这里有一篇文章说明了使用 sql 修补 habtm 表并添加一个 id(作为 pkey):Rails 建模:将 HABTM 转换为 has_many :through。我在使用这种方法时遇到了麻烦,并且可能存在特定于数据库的问题。我最终破坏了连接(habtm)表并创建了一个新的连接模型。那行得通。
一些警告:在这样做之前,我建议在 git 中创建一个分支并将数据库存档,以便在它横向运行时轻松恢复。
这些是步骤:
编辑两个连接模型以使用 has_many 通过
class Physician < ActiveRecord::Base
# has_and_belongs_to_many :patients
has_many :appointments
has_many :patients, :through => :appointments
end
对患者做同样的事情。
创建新的连接模型:
rails g model Appointment physician_id:integer patient_id:integer has_insurance:boolean
编辑上面生成的新迁移文件...请注意,“更改”作为迁移方法不起作用,因为我们正在处理数据。见下文。
在数据库中创建新的连接模型,并通过记录将所有旧的 habtm 关联映射到新的 has_many:
def self.up
create_table :appointments do |t|
t.integer :physician_id
t.integer :patient_id
t.boolean :has_insurance
t.timestamps
end
Physician.find_each {|doc|
doc.patients.each do |pat|
Appointment.create!(:physician_id => doc.id, :patient_id => pat.id, :has_insurance => false )
end
}
# finally, dump the old hatbm associations
drop_table :patients_physicians
end
如果按照 Rails 指南重建旧的 habtm 关联似乎太痛苦了,那就中止。但是请注意,使用这种方法无法再回滚迁移。
def self.down
raise ActiveRecord::IrreversibleMigration
end
相反,要“关闭”,只需终止 git 分支,然后重新加载备份数据库。然后,如有必要,您可以从那里恢复 db:rollback。另一方面,如果 has_many through 记录不需要修改,另一种方法是删除 :id 列,并重命名 db:
def self.down
remove_column :appointments, :id
rename_table :appointments, :patients_physicians
end
我没有测试后者(因为在我的情况下我必须弄乱元数据)。这些想法来自这篇文章:http: //7fff.com/2007/10/31/activerecord-migrating-habtm-to-model-table-suitable-for-has_many-through/。
这是我用于转换团队和用户之间的 has_and_belongs_to_many 关系的迁移:
class CreateTeamMembers < ActiveRecord::Migration
def up
# Create a new table with id and timestamps to replace the old one
create_table :team_members do |t|
t.belongs_to :team
t.belongs_to :user
t.timestamps
end
# Now populate it with a SQL one-liner!
execute "insert into team_members(team_id,user_id) select team_id,user_id from teams_users"
# drop the old table
drop_table :teams_users
end
def down
# This leaves the id and timestamps fields intact
rename_table :team_members, :teams_users
end
end