What did I do wrong with my Rails migrations for Heroku? - ruby-on-rails

I'm trying to add my Address table's text property as the address property of my Brewery table, then delete the Address table. I'm doing this on Heroku after a git push heroku master by running heroku run rake db:migrate.
My first migration which creates the new field for the data works fine. But my second migration fails immediately- it says it can't find the Address table. My third migration never runs, but it's the one that was supposed to delete the Address table to tidy everything up.
What am I doing wrong? These migrations worked on my local box, but are failing on Heroku:
1:
class AddAddressStringToBrewery < ActiveRecord::Migration
def change
add_column :breweries, :address, :string
end
end
2:
class MoveAddressToString < ActiveRecord::Migration
def change
Address.all.each do |address|
brewery = address.brewery
brewery.update(address: address.text)
end
end
end
3:
class DropAddressTable < ActiveRecord::Migration
def change
drop_table :addresses
end
end
My best guess is that Heroku is reading my schema and dropping the table, before running my migrations. I could always stage these migrations in individual git commits to force it to work, but I'd really like to know where I went wrong.
Thanks!

It's because the file names of your migrations are in the wrong order. Rails will migrate files based on the timestamp of the file name. So if you want #2 to run before #3, you have to rename it to a file name timestamp that comes before #3.
Also, you don't show the migration which creates the Address table. The table may not be in your production database.

Try heroku run rake db:migrate to update your production database.

I realized what I did wrong. My push to Heroku with these migrations also deleted my Address model. When I ran them in my local environment it was before I cleaned up the old Address code. I added the Address model back long enough to run the migrations and they all run fine.

Related

How can I properly drop an Active Record Migration?

Among my migrations, I have 3 that pertain to this question. In order, there is CreateEvents < ActiveRecord::Migration. The next down the line is CreateYears < ActiveRecord::Migration. Then the last is AddYearIdToEvents < ActiveRecord::Migration. The last one looks like this...
class AddYearIdToEvents < ActiveRecord::Migration
def change
add_column :events, :year_id, :integer, null: false, index: true
end
end
Now the problem is, whenever I try to drop the entire database (not near deploying to production), I get an obvious error of
ERROR: cannot drop table years because other objects depend on it
DETAIL: constraint events_year_id_fk on table events depends on table seasons
HINT: Use DROP ... CASCADE to drop the dependent objects too.
Now, I'm not a rails expert, but I believe I need to define a def down in that last migration. Rather than def change, do I need a def up and def down? The def down to drop this particular column.
If so, how can I do this. This migration is 20 migrations old. You can't just edit a migration like that can you? Do I add a new migration and just specify a def down? Or is the answer something completely different?
Have you tried rolling back your migrations? This undoes your migrations in reverse order, i.e. starting with the most recent migration.
$ rake db:rollback
If you have 20 migrations and you'd like to rollback all of them, you can use STEP=20
$ rake db:rollback STEP=20
Once you rollback past a migration that you'd like to change, you can change it.
In addition, you should be able to use rake db:drop, which drops the entire database rather than going through each migration in reverse order. If you'd like to drop the database, then recreate it and re-run all the migrations, you can run rake db:reset. Keep in mind this also runs rake db:seed if you have a db/seed.rb file.
And in response to your question of "Rather than def change, do I need a def up and def down?", the answer is no. Newer versions of Rails use def change since (among other reasons) it makes it easier to edit migrations once they are generated, i.e. if you spell a column name incorrectly when adding a column to a table.

adding a new column in a rails database migration

So I've been going through a lot of rails tutorial, and I get that the default for adding a new column to a database is , for example,
rails generate migration add_reset_to_users reset_digest:string reset_sent_at:datetime
The above will add a reset_digest in the form of a string and reset_sent_at in the form of a date to the migration add_reset_to_users
My questions is what if I am clumsy one night at 4 AM and only call the following
rails generate migration add_reset_to_users reset_digest:string
I completely forgot about reset_sent_at but want to implement it the next morning. I made the mistake of adding the link directly to the db file, which was a huge mistake.
In this case what should I do? Do I simply call a new migration such as
rails generate migration add_reset_sent_to_users reset_sent_at:datetime
or is there an even better way?
first, if you have not run your migration, you can directly open the migration file, and add your column to the file, as
def change
add columns :table_name :column_name :column_type
end
In your case, you will modify the file as,
def change
add columns :users :reset_digest :string
add columns :users :reset_sent_at :datetime
end
and then run
rake db:migrate
if you have already ran your migration, and you have not run any other migration after that, you can undo it, by
rake db:rollback STEP=1
and then edit the migration file, and run your migration
Rule of thumb for migrations in Rails is that you always create a new migration file unless you have not already shared your code with others, i.e. pushed to remote repository, otherwise you can just change the old migration after running $ rake db:rollback and everything will be fine, and nobody will know about it, and won't affect other developers work(since it's still on your local repository).
So, I'd encourage you to create a new migration if you have already committed and pushed the code onto remote repository, and changing the old migration file again will hurt other developers productivity. In case of any confusion, always create a new migration:
rails generate migration add_reset_sent_to_users reset_sent_at:datetime
I think it depends what state your rails app is in.
If you were working on a production app then editing migrations is not advisable due to data loss and changes should be made with a new migration.
If your working locally in development then I would edit the migration directly and add the missing column and rerun your migration.
Don't be worried about editing you migrations, just remember to rake db:rollback the migration you are editing before making changes or you will encounter errors.
This is where changing your migration from:
def change
add_column('users', 'reset_digest', :string)
add_column('users', 'reset_sent_at', :datetime) # Would have to perform rollback before adding this line
end
to:
def up
add_column('users', 'reset_digest', :string)
add_column('users', 'reset_sent_at', :datetime) # Added after migration
**rake db:migrate
end
def down
remove_column('users', 'reset_digest', :string)
remove_column('users', 'reset_sent_at', :datetime) # Add this after rollback
**rake db:rollback
end
Allows you to make changes to your migrations before you rake db:rollback
This requires a bit more code but I find it easier when I'm building a new app and things are changing frequently.

Fixing error in deleted migration and table

I'm trying to update my heroku database. The problem: I created an old model & table that we no longer need. That table had previously been migrated to a production server (along with other changes). I did a destroy of the model using:
rails destroy model ReallyLongModelName
That also deleted the migration that created the table.
Later, I created a migration to drop that table.
class Drop_ReallyLongTableName < ActiveRecord::Migration
def change
drop_table :really_long_table_name
end
end
I'm now getting a couple of errors.
First error:
When trying to migrate the database to the production version of the application, I get this error.
Input string is longer than NAMEDATALEN-1 (63)
I'm not sure how to go back and edit the name to avoid the long name, so that it clears
Second error:
When trying to rollback the Drop_ReallyLongTableName migration, its aborts the rake because
rake aborted!
An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: no such table: really_long_table_name
Does anyone have any ideas on how to solve this? Thanks!
Have you tried running this from your Terminal/console:
heroku run console
ActiveRecord::Migration.drop_table(:table_name)
The migration is the way to go but this might be worth a try to see if the table even exists any more (since your second error message seems to indicate that it is no longer there).
Also, and for what it's worth, you can add conditional logic to your DB migrations should you need to in the future
def change
drop_table :table_name if self.table_exists?("table_name")
end

How does the migration work in Rails?

This is a newbie question. Is the migration (rake db:migrate) feature something that one would using during development or it's strictly a production tool for bringing the database up to date?
Ideally you want to use migrations only during development, and then load schema and seed the database in production. In reality, they'll allow you to make some changes and then deploy to production without any harm done.
Migrations allow you to work in iterations even on your database. You don't have to worry about forgetting to add something. When you start, just create the table as you think it's right, and you can fix it with another migration later. That's basically the idea. It takes away the one db script rules them all kind of thing.
A little example, if you have a User model with username and password and you need to add an email field, simply do this
rails generate migration AddEmailToUser # this is a convention, but you can name it however you want
class AddEmailToUser < ActiveRecord::Migration
def change
add_column :users, :email, :string
end
end
the change method will work both ways, when you apply the migration, and also when you need to revert it. It's kind of a neat Rails 3.1 magic.
The old version of migrations would look like this
class AddEmailToUser < ActiveRecord::Migration
def up
add_column :users, :email, :string
end
def down
remove_column :users, :email
end
end
Once you've added the migration, just run rake db:migrate and everything should work just fine. A big advantage of migrations is that if you manually mess up your database, you can easily just do
rake db:drop
rake db:create
rake db:migrate
or
rake db:migrate:reset # this might not work if you messed up your migrations
And you have the correct version of the database created
Migrations keep track of changes in your database schema. All changes with it (renaming column, changing tables, adding indexes etc.) should be done via migration. Thanks to that is really easy to deploy changes across multiple production servers.

Heroku Drop Table Rails Help

I am using Ruby on Rails and I no longer need my table Order so I deleted it using SQLite manager.. How can I make the table deletion take place in heroku?
EDIT
I am getting the error
db/migrate/20110806052256_droptableorders.rb:10: syntax error, unexpected keyword_end, expecting $end
When i run the command
class DropTableOrder < ActiveRecord::Migration
self.up
drop_table :orders
end
self.down
raise IrreversibleMigration
end
end
In case you don't want to create a migration to drop table and cant rollback the previous migrations because you don't want to lose the data in the tables created after that migration, you could use following commands on heroku console to drop a table:
$ heroku console
Ruby console for heroku-project-name
>> ActiveRecord::Migration.drop_table(:orders)
Above command will drop the table from your heroku database. You can use other methods like create_table, add_column, add_index etc. in the ActiveRecord::Migration module to manipulate database without creating and running a migration. But be warned that this will leave a mess behind in the schema_migrations table created by Rails for managing migration versions.
This could only be useful if your application is still under development and you don't want to lose the data you have added on remote staging server on heroku.
Execute following command.Here 'abc' is app name
heroku run console --app abc
Then use,
ActiveRecord::Migration.drop_table(:orders)
It will drop the table 'order'.
Just create a migration like this:
def self.up
drop_table :orders
end
def self.down
# whatever you need to recreate the table or
# raise IrreversibleMigration
# if you want this to be irreversible.
end
and then do a heroku rake db:migrate the next time you push your changes.
You might want to recreate the table in SQLite so that you can run this migration locally as well.

Resources