我们在两个模型之间有一个简单的has_and_belongs_to_many关系。我们希望在该模型中添加一些参数,因此我们需要将其更改为has_many:通过某种模型。如何通过?将has_and_belongs_to_many迁移到has_many?
据我所知,我们需要添加一个id列(以及我们想要的任何列)。但是,我不清楚如何做到这一点。如果我们添加一个整数列:id,那么rails会知道这是'id'主键?
我们使用最新的3.x.
我们在两个模型之间有一个简单的has_and_belongs_to_many关系。我们希望在该模型中添加一些参数,因此我们需要将其更改为has_many:通过某种模型。如何通过?将has_and_belongs_to_many迁移到has_many?
据我所知,我们需要添加一个id列(以及我们想要的任何列)。但是,我不清楚如何做到这一点。如果我们添加一个整数列:id,那么rails会知道这是'id'主键?
我们使用最新的3.x.
这里有一个帖子,说明如何使用sql来修补habtm表并添加一个id(作为pkey):Rails modeling: converting HABTM to has_many :through。我遇到了这种方法的麻烦,并且可能有数据库特定的问题。我最终抛弃了join(habtm)表并创建了一个新的连接模型。这工作。
一些注意事项:在做这件事之前,我建议在git中创建一个分支,并将数据库归档,以便在恢复时轻松恢复。
这些是步骤:
编辑两种连接模型通过
class Physician < ActiveRecord::Base
# has_and_belongs_to_many :patients
has_many :appointments
has_many :patients, :through => :appointments
end
使用的has_many执行相同的患者。
创建新的连接模式:
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
,如果它似乎太痛苦的重建旧的habtm协会评为根据导轨指南,只需中止。但是请注意,用这种方法不能再回滚迁移。
def self.down
raise ActiveRecord::IrreversibleMigration
end
相反,要'下',只需要杀死git分支,然后重新加载备份数据库。然后,如果需要,可以从那里恢复db:rollback。在另一方面,如果通过记录的has_many不需要修改,另一种方法是刚落: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/。
谢谢蒙蒂,你救了我。非常感谢 – Zakaria 2015-06-08 04:19:41
引用假设你的数据库表上,由铁轨产生的has_and_belong_to许多是patients_physicians
所有你需要做的就是生成一个这样的模型
rails g model patients_physician --skip-migration
那么你可以添加你需要迁移命令,如任何列做
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
非常好的答案。只需申请,无副作用。 'habtm'关联给出的所有以前的函数将仍然可用。 (如'<<或'clear') 唯一需要注意的是新模型的名称*必须*是您写的:'patients_physician'单数,而不是复数。 – 2016-03-29 18:29:00
这是我用于转换团队和用户之间的关系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
这是一个很好的答案,因为它在回滚时保留数据! – 2016-02-19 10:38:38
对于已经在生产中运行的应用程序,这可能不是最好的解决方案,特别是当用户可能定期更新/插入/删除表中的记录时。 – Todd 2016-06-20 19:49:34