【问题标题】:Change serialization type on column while preserving data - Rails在保留数据的同时更改列上的序列化类型 - Rails
【发布时间】:2015-01-07 00:33:39
【问题描述】:

我有一个项目已经启动,并且正在进行重大重构,清理我和我的同事在此过程中犯下的所有错误。在我们的人员表中,我们决定将联系信息存储为序列化哈希。但是,这导致了每个记录只能使用一个唯一标识符的问题(即,如果 Person.first.contact_info[:email] = 'test@test.com'...... 现在此人无法输入另一个联系人条目并将其称为“电子邮件”)。

我的问题是,是否有一种简单的方法可以编写迁移/rake 任务来将列序列化更改为Array,同时保留所有数据?我打算添加/删除一个临时列,但现在我意识到我不能简单地更改模型中的序列化类型在运行它之前,因为它不会被正确读取。这似乎是一个问题 22。关于如何实现这一点的任何想法?我希望一次性迁移或执行所有这些任务,以便一次部署到服务器将可靠且安全地影响更改。谢谢。

【问题讨论】:

    标签: ruby-on-rails activerecord serialization


    【解决方案1】:

    所以......我拼凑了一个解决方案。这是相当丑陋的,但它的伎俩。花了一些研究,但我没有使用 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
    

    【讨论】:

      【解决方案2】:

      按照this post 中的说明,复制列,将其取消,然后手动加载原始 YAML 会更简洁

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-15
        • 2010-11-18
        • 1970-01-01
        • 2023-04-04
        • 2016-07-16
        • 2013-09-17
        • 2018-05-21
        • 2015-08-03
        相关资源
        最近更新 更多