如何在不删除现有记录的情况下通过ActiveRecord模型替换has_many的一侧?

时间:2017-02-21 01:11:05

标签: ruby-on-rails-4 activerecord database-migration

我有一个带有has_many关联的ActiveRecord模型。事件模型有一个场地列(字符串),我需要提取并转换为单独的模型。

# Original Models

class Event < ActiveRecord::Base
  has_many :booking_events, dependent: :destroy
  has_many :bookings, through: :booking_events
end

class Booking < ActiveRecord::Base
  has_many :booking_events, dependent: destroy
  has_many :events, through: :booking_events
end    

class BookingEvent < ActiveRecord::Base
  belongs_to :event
  belongs_to :booking
end


# Refactored models

class Event < ActiveRecord::Base
  belongs_to :venue
end

class Venue < ActiveRecord::Base
  has_many :events

  has_many :booking_venues, dependent: :destroy
  has_many :bookings, through: :booking_venues
end

class Booking < ActiveRecord::Base
  has_many :booking_venues, dependent: destroy
  has_many :venues, through: :booking_venues
end    

class BookingVenue < ActiveRecord::Base
  belongs_to :venue
  belongs_to :booking
end

由于Venue现在是多对多关系中的一方,而不是事件我添加了场地ID并使用迁移查找并关联正确的venue_id。

class BookingVenue < ActiveRecord::Base
  belongs_to :event # not needed, trying to remove
  belongs_to :booking
  belongs_to :venue
end

下一步是我删除不再需要的事件关联,但是当我删除列或将event_id设置为nil时,会从数据库中删除记录。我认为这是因为dependent: destroy

我认为我正在接近这个,但我不知道这是迁移数据或更新关联的标准或Rails方式。任何建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

我最终通过关联表创建新的has_many并更新/重命名模型定义以使用新模型。

以下参考资料是关键:https://makandracards.com/makandra/15575-how-to-write-complex-migrations-in-rails

然后我将模型类定义添加到迁移文件中,以便ActiveRecord支持查询原始模型。对于由于依赖值而没有改变但限制数据操作的模型定义,我使用Rails中的开放类概念在迁移中暂时覆盖关联,以将依赖关联从destroy更改为nullify。

例如:

#migration file

class CreateVenue < ActiveRecord::Migration

  # temporarily override dependent assocation
  class Event < ActiveRecord::Base
    # has_many :booking_event, dependent: :destroy
    has_many :booking_event, dependent: :nullify
  end    

  # temporary model class definition for ActiveRecord support
  class BookingEvent < ActiveRecord::Base
  end

   def change
     # Used the previous model support to loop through and create
     # the new association objects

     # overriding the dependent: :destroy value above allows 
     # for deleting this table without deleting the other records
     drop_table :booking_events
   end
end