Monday, 27 January 2014

Loading records from YAML to Rails

Occasionally you need to save data from your database, to be loaded back in at a later data, or to be loaded into another database. YAML makes saving the data trivial:

  def self.save
    File.open('data.yml', 'w') do |out|   # To file
       YAML.dump(MyRecord.all.to_a, out)
    end
  end

Loading it into Rails again is not as straighhtforward. Well, getting it into Rails is easy, getting Rails to save the data to the database is not.

There are two issues. The first is that Rails will use the SQL UPDATE method when you try to save the date. That is not going to work unless there is already a record present in the database. I found the simplest way around that s to use raw SQL to create each record with the correct ID, and then use save to update that record with the correct values (obviously you could do all that in one step, which would avoid the second issue, but require more complicated SQL).

The second issue is that ActiveRecord.save will only update attributes that are flagged as dirty, so you need to flag every column.

This is the solution I ended up with:

  def self.load
    ary = YAML.load_file "data.yml"
    ary.each do |data|
      ActiveRecord::Base.connection.execute(
            "INSERT INTO my_records (id) VALUES (#{data.id})"
      )
      MyRecord.column_names.each { |s| eval("data.#{s}_will_change!") }
      data.save
    end