DB Migration and Callbacks [JRuby 1.5.2 or Rails 2.2.3]
The Background
We have a rails migration script as below: ... ... 0011_update_column1_for_internal_projects.rb ... ... 0022_create_audits.rbWe created after_create/update/delete callbacks for the InternalProject model that updates the Audits table to 开发者_开发百科track the event that occured on the model.
The Code Snippet
The DB migrate script - 0011 - has its self.up method defined as below:def self.up
InternalProject.all.each do |project|
project.column1 = project.column2
project.save!
end
end
The Side Effect
With 0022 script, we landed in a situation where the script 0011 fails to migrate, because we have test fixtures to load some seed data for the internal projects. Now this one fails because while saving the InternalProject the call back gets triggered, and at that instant of DB state, because 0022 hasn't run, the Audit table wouldnt exist and so we get a SQL error lamenting that the table doesn't exist.My Question(s)
1. How do I fix the 0011 DB migrate script, to prevent the callbacks from being called upon the InternalProject being saved? I would like to know the neat way to do this. 2. Makes me wonder if such an update script be deleted. Is it a bad idea? Should we have scripts for data manipulation in DB migration? 3. Should the DB migration scripts have data manipulation scripts, is there something that we can do about it?Try putting this in your 0011 migration
def self.up
InternalProject.all.each do |project|
project.column1 = project.column2
project.save(:validate => false) # don't run validations! (notice we're calling `save` and NOT `save!`)
end
end
See above
It is normal to manipulate data in your migrations to have it conform to the schema evolutions. However, when deploying your project to a new environment (e.g. the first time you deploy to production), you should run
rake db:create
instead of running the migrations.Not sure I understand your question, but it makes sense to have the data manipulation within the migration (instead of a separate script). Keep what belongs together, together. That said, there is nothing preventing you from having a separate migration file to migrate your data.
I ended up the inserting a ANSI compatible SQL script in the code block as below. Couldn't think of any fail-proof way.
def self.up
InternalProject.all.each do |internal_project|
InternalProject.connection.execute("UPDATE projects SET sales_leader='#{internal_project.owner_name}' where type='InternalProject' and owner_id=#{internal_project.owner_id}")
end
end
Should anyone think of/have a better solution than this, please do post your thought/experience.
精彩评论