Skip to content

Instantly share code, notes, and snippets.

@creeefs
Last active August 29, 2015 14:15
Show Gist options
  • Select an option

  • Save creeefs/4dbe9e93a141bb45a4de to your computer and use it in GitHub Desktop.

Select an option

Save creeefs/4dbe9e93a141bb45a4de to your computer and use it in GitHub Desktop.
Does ActiveRecord have an API to typecast AR attributes? To provide some background, I'm prepping for a zero downtime deploy, so I need to migrate existing production data to the new domain model without having the create_association method available.
ActiveRecord::Base.connection_pool.with_connection do |conn|
conn.execute("INSERT INTO `comments` (`post_id`, `created_at`, \
`id`, `updated_at`) VALUES (x'535cc052b670416c8a8f90a6a2deb611', '2015-02-19 23:02:50', \
x'67b5c8191e4146708437d6c69cdb08d0', '2015-02-19 23:02:50')")
end
@sgrif

sgrif commented Feb 20, 2015

Copy link
Copy Markdown

I'd create a throw-away AR class in the model itself, and just go through the normal Active Record API.

class WhateverMigration < ActiveRecord::Migration
  class TempModel < ActiveRecord::Base
    self.table_name = "comments"
  end

  def up
    Coment.create!(post_id: "binary data", created_at: Time.now, id: "binary data", updated_at: Time.now)
  end
end

@creeefs

creeefs commented Feb 20, 2015

Copy link
Copy Markdown
Author

@sgrif First off, thank you for the speedy response! I really appreciate it 😄

Unfortunately (and this was my fault for not giving enough background), our DB servers don't have Rails available, so our dev team typically sends the DBAs raw SQL corresponding to our migrations. Now that I think about it, we could probably run the rake commands on a separate machine while specifying the appropriate environment, but that's probably work for another day. Also, I should note that our app is deployed on Torquebox, so my intention was to run a script using Torquebox's console to clean up the data.

I ended up figuring out a solution, but if you're still interested here's a more complete description of my situation. Currently in production, we have a parent Ad object, which has_one :ad_statistic. I have a pending pull request that essentially renames AdStatistic to AdReport. Given the zero downtime requirement, I generated a fresh ad_reports table (rather than renaming ad_statistics to ad_reports) to ensure backwards compatibility. So, to migrate the old data to the new ad_reports table I sketched out the following script.

Ad.all.each do |ad|
  if ad.ad_statistic.present?
    ad.create_ad_report!(
      impressions: ad.ad_statistic.impressions,
      reach: ad.ad_statistic.reach,
      spend: ad.ad_statistic.spend,
      clicks: ad.ad_statistic.clicks
    )
  else
    ad.create_ad_report!({})
  end
end

But, in testing the script on the current app, I realized that the create_ad_report method was unavailable since the corresponding code has yet to be merged. So, that's when I moved down an abstraction to write raw SQL. The challenge then became making sure that the interpolated values were properly typecasted (I think that's the term).

Ad.all.each do |ad|
  if ad.ad_statistic.present?
    ActiveRecord::Base.connection_pool.with_connection do |conn|
      conn.execute("INSERT INTO `ad_reports` (`ad_id`, `created_at`, `id`, `reach`, `updated_at`) VALUES (#{ad.id.quoted_id}, '#{Time.zone.now.to_s(:db)}', #{UUIDTools::UUID.random_create.quoted_id}, #{ad.ad_statistic.reach}, '#{Time.zone.now.to_s(:db)}');")
    end
  else
    ActiveRecord::Base.connection_pool.with_connection do |conn|
      conn.execute("SQL INSERT")
    end
  end
end

Note: we are using ActiveUUID, and I found the corresponding helper methods to generate the appropriate SQL values.

Hopefully, that provides more context behind the question. Fortunately, I'm dealing with simple MYSQL data types, but I guess I'm still curious if there's a way to appropriately typecast the attribute before interpolating the value. I also realize that the whole point of ActiveRecord is to abstract away such details, so perhaps it would run counter to the library's intentions. Any additional thoughts would be appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment