I'm trying to convert a column in my Rails app, for arguments sake let's pretend I'm trying to change the age
column in my users
table to a string representation rather than an int.
In my migration I have this;
def.self up add_column :users, :age_text, :string users = User.find(:all) users.each do |u| u.age_text = convert_to_text(u.age) u.save end end def self.convert_to_text(number) #code here to convert 1 to 'one' etc end
But it doesn't seem to be working, is what I'm attempting here even possible with migrations?
A Rails migration is a tool for changing an application's database schema. Instead of managing SQL scripts, you define database changes in a domain-specific language (DSL). The code is database-independent, so you can easily move your app to a new platform.
Migrations are a convenient way to alter your database schema over time in a consistent way. They use a Ruby DSL so that you don't have to write SQL by hand, allowing your schema and changes to be database independent. You can think of each migration as being a new 'version' of the database.
When you run db:migrate, rails will check a special table in the database which contains the timestamp of the last migration applied to the database. It will then apply all of the migrations with timestamps after that date and update the database table with the timestamp of the last migration.
On databases that support transactions with statements that change the schema, migrations are wrapped in a transaction. If the database does not support this then when a migration fails the parts of it that succeeded will not be rolled back. You will have to rollback the changes that were made by hand.
What you're trying to do is possible, and I would say the correct thing to do.
You need, though, to reload the column info for the model classes you're updating in the migration, so that Rails knows about the new columns. Try this:
def.self up add_column :users, :age_text, :string User.reset_column_information users = User.find(:all) users.each do |u| u.age_text = convert_to_text(u.age) u.save end end
On a separate note, please note that if your table is large, doing updates one by one will take a looong time.. Be careful with that.
Since I'm new here I can't comment on the above so I'll add my own answer.
GENERALLY manipulating data in migrations is a BAD idea. Migrations with direct model access can get stuck if the model logic changes.
Imagine in your second migration you've added a new column. You want to seed that column with new data.
Let's also say a few weeks later you add a new validation to the model - a validation that operates on a field that does not yet exist in your second migration. if you ever were to construct the database from migration 0, you'd have some problems.
I strongly suggest using migrations to alter columns and other means to manage database data, especially when moving to production.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With