Add some regular ruby code in your rails migrations
Warning : This article was written a while ago, my views may have changed and this may not be relevant anymore.
For long, I’ve used rails migrations only as a way to update my database schema, no more.
Today, I had to do a more complex operation.
I have a Message model and a Conversation model; for historical reasons, the read / unread was stored in the Message model, but I actually don’t need to keep a track of what message was read or not, only conversations.
So I had to do a simple migration that would create a filed in the Conversation model and remove it from the Message model.
However, I’ll have to apply this migration to production, and this will cause some data loss, how can I mark as unread the unread conversations ?
A few months ago, I would have created a complex script for doing that.
Today, I tried something pretty intuitive :
class MoveUnreadToConversation < ActiveRecord::Migration
def change
conversations = {}
Conversation.includes(:messages).each do |conversation|
conversations[conversation.id] = (conversation.messages.count { |m| m.read_user == false}) > 0
end
remove_column :messages, :read_user
add_column :conversations, :unread, :boolean, :default => true
conversations.each do |index, unread|
c = Conversation.find(index)
c.unread = unread
c.save
end
end
end
And it works !
Just add some regular ruby code to your migration, it will work like a charm, the schema is updated and reloaded after the database operations so you won’t have any problem with ActiveRecord.
This may seem to be a pretty standard feature of rails migrations, but I did not know it until today, thanks to ruby and rails, I can learn new things every single day !
Happy Rubying !