我有一个Rails应用程序,其关系如下:
region.rb
class Region < ActiveRecord::Base
has_many :facilities
end
facility.rb
class Facility < ActiveRecord::Base
belongs_to :region
end
我想稍微扩展一下功能,以便设施一次可以属于多个区域。我相信我可以通过has_many_through关系来做到这一点,但是我需要一些指导才能将现有的has_many转换成有很多通道。我了解如何创建和连接连接表,但我如何获取现有数据并进行翻译呢?
所以举个例子。在设施对象上有region_id
,因为设施可以属于多个区域,我可能需要region_ids
字段并将区域集合铲入该列,然后填充该列通过连接表的关联的另一面。我有这个部分几乎已经找到了前进和连接协会。但我不确定如何获取现有数据并对其进行翻译,以便在我更改模型关联时应用程序不会中断。
非常感谢任何建议。
答案 0 :(得分:4)
我建议您始终使用has_many :through
代替HBTM。
要建立这种关系,您需要进行以下设置:
# region.rb
class Region
has_many :facility_regions
has_many :facilities, through: :facility_regions
end
# facility.rb
class Facility
has_many :facility_regions
has_many :regions, through: :facility_regions
end
# facility_region.rb
class FacilityRegion
belongs_to :facility
belongs_to :region
end
当然,您还需要创建迁移:
rails g migration create_facility_regions facility_id:integer region_id:integer
# in this migration create a uniq index:
add_index :facility_regions, %I(facility_id region_id), name: :facility_region
rake db:migrate
关于从一个数据库状态迁移到另一个数据库状态。
我认为这应该不是问题。
1)不要删除之前的关系(在模型中保留has_many :facilities
和belongs_to :region
)。
2)创建新表并将新关联添加到类(我展示的)时创建一个新的迁移:
rails g migration migrate_database_state
3)编写脚本,它将在db中创建新记录(以反映事物的当前状态):
ActiveRecord::Base.transaction do
Facility.where.not(region_id: nil).find_each do |facility|
next if FacilityRegion.find_by(falicity_id: facility.id, region_id: facility.region_id)
FacilityRegion.create!(facility_id: facility.id, region_id: facility.region_id)
end
end
4)将此脚本放入上次创建的迁移并运行它(或在没有迁移的控制台中,效果相同)。
5)成功运行脚本后,创建新的迁移,从region_id
表中删除facilities
并从模型中删除这些关联定义(has_many :facilities
和belongs_to :region
)
一定是它。我可能会犯一些错别字,确保我没有错过任何内容和
答案 1 :(得分:1)
你需要添加另一个模特,一个&#34;中间人&#34;名为FacilityRegion.rb,如下所示:
class Facility < ActiveRecord::Base
has_many :falicity_regions
has_many :regions, through: falicity_regions
end
class FacilityRegion < ActiveRecord::Base
belongs_to :region
belongs_to :facility
end
class Region < ActiveRecord::Base
has_many :falicity_regions
has_many :facilities, through: falicity_regions
end
答案 2 :(得分:0)
如果您想使用belongs_and_has_many
关系,则需要:
rails g migration CreateJoinTableRegionsFacilities regions facilities
然后
rake db:migrate
现在,您的关系应该是:
Region.rb:
class Region < ApplicationRecord
has_and_belongs_to_many :facilities
end
Facility.rb
class Facility < ApplicationRecord
has_and_belongs_to_many :regions
end
要填充新的联接表,您需要在控制台中:
Region.all.find_each do |r|
Facility.where(region_id: r.id).find_each do |f|
r.facilities << f
end
end
现在,您可以分别在Facility和Region表中保留列region_id
和facility_id
的列,也可以创建一个迁移来删除它。