Rails 将 has_many 关系转换为 has 和 belongs to many
Rails Converting a has_many relationship into a has and belongs to many
我有一个 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 转换为具有许多通过的关系。我了解如何创建和连接连接 table,但我将如何获取现有数据并进行转换?
例如。在设施对象上有 region_id
,因为设施可以属于多个区域,我可能需要一个 region_ids
字段并将区域集合铲到该列中,然后填充另一侧通过加入 table 加入协会。就向前推进和建立协会而言,我已经很清楚这部分了。但我不确定如何获取现有数据并将其转换过来,以便在我更改模型关联时应用程序不会中断。
如有任何建议,我们将不胜感激。
您需要添加另一个模型,一个名为 FacilityRegion.rb 的 "middle guy",如下所示:
facility.rb
class Facility < ActiveRecord::Base
has_many :falicity_regions
has_many :regions, through: falicity_regions
end
facility_region.rb
class FacilityRegion < ActiveRecord::Base
belongs_to :region
belongs_to :facility
end
region.rb
class Region < ActiveRecord::Base
has_many :falicity_regions
has_many :facilities, through: falicity_regions
end
我建议你始终使用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
UPD
关于从一种数据库状态迁移到另一种数据库状态。
我觉得应该问题不大
1)不要删除你之前的关系(模型中保留has_many :facilities
和belongs_to :region
)。
2) 创建新的 table 并将新的关联添加到 类(我展示的)时创建新的迁移:
rails g migration migrate_database_state
3) 编写脚本,它将在数据库中创建新记录(以反映事物的当前状态):
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) 脚本成功 运行 后,创建新的迁移,从 facilities
table 中删除 region_id
并删除这些关联定义(has_many :facilities
和 belongs_to :region
) 来自模型。
一定是。我可能有一些错别字,请确保我没有遗漏任何内容
如果你想使用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
为了填充新连接 table,您需要在控制台中:
Region.all.find_each do |r|
Facility.where(region_id: r.id).find_each do |f|
r.facilities << f
end
end
现在,您可以分别在 Facility 和 Region table 中保留列 region_id
和 facility_id
,或者您可以创建一个迁移来删除它。
我有一个 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 转换为具有许多通过的关系。我了解如何创建和连接连接 table,但我将如何获取现有数据并进行转换?
例如。在设施对象上有 region_id
,因为设施可以属于多个区域,我可能需要一个 region_ids
字段并将区域集合铲到该列中,然后填充另一侧通过加入 table 加入协会。就向前推进和建立协会而言,我已经很清楚这部分了。但我不确定如何获取现有数据并将其转换过来,以便在我更改模型关联时应用程序不会中断。
如有任何建议,我们将不胜感激。
您需要添加另一个模型,一个名为 FacilityRegion.rb 的 "middle guy",如下所示:
facility.rb
class Facility < ActiveRecord::Base
has_many :falicity_regions
has_many :regions, through: falicity_regions
end
facility_region.rb
class FacilityRegion < ActiveRecord::Base
belongs_to :region
belongs_to :facility
end
region.rb
class Region < ActiveRecord::Base
has_many :falicity_regions
has_many :facilities, through: falicity_regions
end
我建议你始终使用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
UPD
关于从一种数据库状态迁移到另一种数据库状态。
我觉得应该问题不大
1)不要删除你之前的关系(模型中保留has_many :facilities
和belongs_to :region
)。
2) 创建新的 table 并将新的关联添加到 类(我展示的)时创建新的迁移:
rails g migration migrate_database_state
3) 编写脚本,它将在数据库中创建新记录(以反映事物的当前状态):
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) 脚本成功 运行 后,创建新的迁移,从 facilities
table 中删除 region_id
并删除这些关联定义(has_many :facilities
和 belongs_to :region
) 来自模型。
一定是。我可能有一些错别字,请确保我没有遗漏任何内容
如果你想使用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
为了填充新连接 table,您需要在控制台中:
Region.all.find_each do |r|
Facility.where(region_id: r.id).find_each do |f|
r.facilities << f
end
end
现在,您可以分别在 Facility 和 Region table 中保留列 region_id
和 facility_id
,或者您可以创建一个迁移来删除它。