所以......我拼凑了一个解决方案。这是相当丑陋的,但它的伎俩。花了一些研究,但我没有使用 rake 就成功了。这是迁移:
class ChangeContactInfoSerializationTypeOnPerson < ActiveRecord::Migration
def up
# Add temp column and its serialization
add_column :people, :temp_contact_info, :text
contents = File.read('app/models/person.rb')
contents.gsub!(/serialize[\s]*:contact_info,[\s]*Hash/, "serialize :contact_info, Hash \n serialize :temp_contact_info, Array")
person_file = File.open('app/models/person.rb', 'w')
person_file.puts contents
person_file.close
# Write data into temp column
Person.all.each do |p|
arr_of_hsh = []
p.contact_info.each do |k,v|
arr_of_hsh.push({k => v})
end
p.update!(temp_contact_info: arr_of_hsh)
end
# Remove original column and change serialization
remove_column :people, :contact_info
contents.gsub!(/serialize[\s]*:contact_info,[\s]*Hash/, "serialize :contact_info, Array")
person_file = File.open('app/models/person.rb', 'w')
person_file.puts contents
person_file.close
# Re-add original column and reload the model file
add_column :people, :contact_info, :text
Object.send(:remove_const, 'Person')
load 'person.rb'
# Copy data back into changed column
Person.all.each do |p|
p.update!(contact_info: p.temp_contact_info)
end
# Remove temp column and its serialization
remove_column :people, :temp_contact_info
contents.gsub!(/[\s]*serialize :temp_contact_info, Array/, '')
person_file = File.open('app/models/person.rb', 'w')
person_file.puts contents
person_file.close
end
def down
# Add temp column and its serialization
add_column :people, :temp_contact_info, :text
contents = File.read('app/models/person.rb')
contents.gsub!(/serialize[\s]*:contact_info,[\s]*Array/, "serialize :contact_info, Array \n serialize :temp_contact_info, Hash")
person_file = File.open('app/models/person.rb', 'w')
person_file.puts contents
person_file.close
# Write data into temp column
Person.all.each do |p|
hsh = {}
p.contact_info.each do |i|
hsh[i.first[0]] = i.first[1] if hsh[i.first[0]].nil?
end
p.update!(temp_contact_info: hsh)
end
# Remove original column and change serialization
remove_column :people, :contact_info
contents.gsub!(/serialize[\s]*:contact_info,[\s]*Array/, "serialize :contact_info, Hash")
person_file = File.open('app/models/person.rb', 'w')
person_file.puts contents
person_file.close
# Re-add original column and reload the model file
add_column :people, :contact_info, :text
Object.send(:remove_const, 'Person')
load 'person.rb'
# Copy data back into changed column
Person.all.each do |p|
p.update!(contact_info: p.temp_contact_info)
end
# Remove temp column and its serialization
remove_column :people, :temp_contact_info
contents.gsub!(/[\s]*serialize :temp_contact_info, Hash/, '')
person_file = File.open('app/models/person.rb', 'w')
person_file.puts contents
person_file.close
end
end