views:

257

answers:

1

I was doing this kind of thing in my migrations:

add_column :statuses, :hold_reason, :string rescue puts "column already added"

but it turns out that, while this works for SQLite, it does not work for PostgreSQL. It seems like if the add_column blows up, even if the Exception is caught, the transaction is dead and so the Migration can't do any additional work.

Is there any non-DB sepecific ways to check if a column or table already exist? Failing that, is there any way to get my rescue block to really work?

+1  A: 

You could check the column ActiveRecord style, assuming you've created a model for the table at this point:

Status.column_names.include?("hold_reason")

If you'll be doing it a lot you could make it a method:

def safe_add_column table_name, column_name, type, options
  unless table_name.to_s.singularize.camelcase.constantize.column_names.include?(column_name.to_s)
    add_column table_name, column_name, type, options
  else
    announce "Column #{column_name} already exists in table #{table_name}"
  end
end

However I'm not quite sure if this holds up if multiple migrations are run at once. I guess you could trigger a reload if necessary to update the Model metadata.

Also I haven't run this code for bugs, but the concept is sound.

EmFi
My guess is that each migration runs in its own transaction, so forcing a reload (if necessary) should do the trick. I'll check it out and let you know, the idea looks sound.
Yar
Not really. ActiveRecord gets the column layout from that database. I'm not sure when that information is loaded and if and when it's updated. So I mentioned the reloading to be safe.
EmFi
Sorry, I wasn't clear. My point was this: DURING a migration even reloading wouldn't update the ActiveRecord. I think it depends on the transaction level, etc., but from what I can gather, each migration is one transaction, so the Model wouldn't know that a column has been added until the migration is done. On the other hand, since Status (in your example) is just a simple class, you could simplify your safe_add_column... method to define the class and do the check, eliminating the dependency on the model being present whatsoever. THANKS for the answer and the comments.
Yar