Thursday, April 15, 2010

Tip of the day: Keep the database timestamp and Time.now in sync

I stumbled across a situation when I have to schedule a job and I have to store today's weekday. I am also storing the schedule's created_at/ updated_at time in datetime format.

To store today's weekday, I said:
weekday = Time.now.wday
>> 4   #Thursday

When I stored the record
Schedule.first.created_at.wday
>> 3  #Wednesday

Why?

I dug in more and here are the facts.
We so say in environment.rb file:
config.time_zone = 'UTC'
But this applies to only the created_at/updated_at attributes and sets up the default timezone for the database and never applies to Time.now


So to keep Time.now in sync we have to set ENV['TZ'] in environment.rb file.


Again in console:
weekday = Time.now.wday
>> 3   #Wednesday


Schedule.first.created_at.wday
>> 3  #Wednesday

:)

Friday, April 2, 2010

Change column type from text to string in oracle

I think I have never encountered this issue until today. On my current Ruby on Rails project I am using Oracle as the database. I have a user model, which has an attribute email and the requirement was that a user can have more than one email id (separated by comma). I initially thought that I should use :text type, as I literally forgot that I am writing a migration against oracle database. Later, when the actual requirement come into the picture, I had to revise as user can have just one email-id and I started thinking about changing the type from :text to string.

There were two reasons to change the column type:
1. As per the requirement, user cannot have so many email-ids
2. Changing the column type from clob to string in oracle would give good performance boost


I decided to change the column type by simply using :
change_column :users, :email, :string, :limit => 4000

D:\rubyapp>rake db:migrate
(in D:/rubyapp)
==  ChangeEmailColumnTypeToStringInUsers: migrating ===========================
-- change_column(:users, :email, :string, {:limit=>4000})
rake aborted!
An error has occurred, all later migrations canceled:

OCIError: ORA-22859: invalid modification of columns: ALTER TABLE users MODIFY email VARCHAR2(4000)

(See full trace by running task with --trace)

Failed! But why?

I came across: http://snippets.dzone.com/posts/show/3022

I followed the same pattern:
1. Add a  temporary column with type as string (varchar2 in local)
2. Update all the records and copy text from email column to temporary column
3. Remove email column
4. Rename temporary column to email

I decided to not to run oracle commands in migration.

Here is how my migration now looks like:

class ChangeEmailColumnTypeToStringInUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :email_temp, :string, :limit => 200
    User.all.each do |user|
      user.update_attribute("email_temp", user.email)
    end
    remove_column :users, :email
    rename_column :users, :email_temp, :email
  end

  def self.down
    add_column :users, :email_temp, :text
    User.all.each do |user|
      user.update_attribute("email_temp", user.email)
    end
    remove_column :users, :email
    rename_column :users, :email_temp, :email
  end
end

Very simple!