I need to replace a column in my user model with an alias_attribute; e.g., what used to be a column named ‘email’ needs to be replaced with:
alias_attribute :email, :emailaddr
Is there any way to do this in a migration, or do I just have to run a migration to remove the email column and then modify my User model manually? I suppose I could add a simple sed command to add/remove the alias_attribute line in the model so that my migration is reversible, but I wonder if there’s a better way…
The migration (change_column, I presume) should be reversible regardless of what is in your model. Your tests might fail if you reverse/apply a migration and do nothing else, but… don’t do that. Reverse the migration and then revert your commit (which had the migration and the change to your model) if you need to.
I agree that’s the goal, and using sed is how I got it all to work. This migration does what I want and is reversible:
class AddAliasToUser < ActiveRecord::Migration
def up
remove_column :users, :email
cmd = <<-EOF
sed -e '/include Clearance::User/a\
alias_attribute :email, :emailaddr\' -i.bak app/models/user.rb
EOF
ret = system(cmd)
end
def down
add_column :users, :email, :string
cmd = <<-EOF
sed -e '/alias_attribute :email/d' -i.bak app/models/user.rb
EOF
ret = system(cmd)
end
end
You definitely do not want to use migrations in this manner.
Migrations are for updating your database schema, not for altering your classes. There are any number of things that can go wrong if you continue to do this. What if at some point, you replace your simple attribute with an actual method? What will this do to your migration? What happens when you deploy to an environment that doesn’t want to let your write to your app directory (e.g. heroku)?
Make your schema change in your migration. Make your class change in that class. Commit both. To revert that change, reverse the migration the rollback your commit. Your git history manages changes to your class, not migrations.