Heroku rake db:migrate - ruby-on-rails

Heroku is telling me that there are migrations that haven't been run, when clearly they have been. It looks like it is behind one migration. How could I solve this problem.
When I run rake db:migrate it tells me rake aborted Mysql2::Error: Duplicate column name. I know these fields have already been created, also pretty sure that migration ran, as those fields don't exist in any other migration and rake db:migrate runs just fine on my local system.
How can I fix this? I think Heroku just didn't realize it already ran that migration. How can I tell it "you already ran migration xxx"?

That probably means you ran it once, but it failed; table alterations in mysql are not transactional, so you can get left in a bad state. Some of the changes may have run, but not all of them.
The only thing you can do is determine which parts already ran, comment out those line in the migration, commit and push and run the migration, bypassing the parts that already ran.

If a migration is incompletely applied, do one of the following:
Use the dbconsole to undo the changes that were applied and then run the migration again, or
make the remaining schema changes manually using the dbconsole and then insert a record into the schema_migrations table.
Depend on what types of changes are in the migration script, you'll need to decide which of the above is easiest. If the changes already applied are destructive changes, such as dropping a column or table, you could recreate the column or table so that the migration will be able to run. If the remaining changes are simple to translate into SQL, then that might be easier.
Inserting a record into the schema_migrations table will allow the app to think that the migration was successfully applied. Do this only if you're absolutely satisfied that the migration changes were completely applied. It has one column, version, which will need to contain the numeric part of the migration filename.
http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
http://guides.rubyonrails.org/migrations.html
Finally, this is an example of why you should use Postgres instead of MySQL. Postgres is able to roll back (most) schema changes in a transaction, so you wouldn't be left with a half-applied migration.

Related

I can't rollback migrations, because the migration file does not exist

I added a migration in branch "add_dogs" with migration db/migrate/20221220155010_create_dogs.rb, and ran db:migrate.
Later on, I changed branches (without a merge), and ultimately abandoned the "new_dogs" branch.
Later later on, I checked out "add_cats" branch with db/migrate/20221101010101_create_cats.rb, and ran db:migrate. So far, all is well.
But then I tweak the "add_cats" migration (before committing anything), and ran db:rollback so I can run it again. I get this error:
ActiveRecord::UnknownMigrationVersionError:
No migration with version number 20221220155010.
I can still run db:migrate on new migrations just fine, but not db:rollback or db:migrate:redo.
This makes sense, because the database has a record of applying 20221220155010, but that migration file no longer exists, so there is no way to roll it back.
How can I get past this?
Here are three ways to deal with a missing migration file, depending on your needs and access:
For a quick temporary fix, you can roll back just the migration you're currently editing so you can run it again. This may be useful if the other migration is still in the pipeline on the other branch and both eventually will get merged.
rake db:migrate:down VERSION=20230101010101
// This is the version of the migration you WANT to rollback, not the missing one.
If the missing migration will never come back, you want a permanent fix. The simplest way is to remove that record from the database. You can do this from your favorite SQL client, rails console, etc. (I suppose you could even write a migration to do that, but that seems mighty sketchy.)
DELETE FROM schema_migrations WHERE version = '20221220155010'
-- This is the version of the migration that is MISSING, not the one you are working on.
If you don't have direct access to the database for whatever reason, you can give Rails a placebo to rollback. Ensure the timestamp in the filename matches the missing migration's version number.
Create a file named db/migrations/20221220155010_just_kidding.rb:
class JustKidding < ActiveRecord::Migration
def change
# nothing to see here.
end
end
Then, rails db:rollback will roll back that no-op migration and delete 20221220155010 from the schema_migrations table. You can now delete the placebo migration forever and you'll be in good shape as far as running migrations and rollbacks.
However...don't forget that the effects of the old migration are still in your schema. Maybe you're stuck with a new, unused 'dogs' table or an extra column on a table. Maybe that's benign on your dev box, but you certainly don't want that cruft on a production environment. All the advice in this answer assumes you're on a throw-away environment and that the effects of the old migration aren't a problem. Tearing down your whole database and rebuilding may become a more attractive option in this case.
One of the realy take-aways here is... don't let this happen in the first place! Ideally, you should rollback any new, uncommitted migrations before changing away from a branch. But...things happen...
p.s. If there is a way to do this from the command line, I'd love to learn it. I'm imagining something like rails db:migrate:delete VERSION=20230101010101 might be handy in a hackish kind of way.

How do I fix my database when I've deleted the current migration file?

My problem is that I at some point was doing some spiking and I migrated my database with a migration that I had created in the spike branch. Then I switched back to my master branch(I never committed the migration). Now that migration is perpetually in my database and this is making it impossible to migrate my database.
when I run
ActiveRecord::Migrator.get_all_versions
in the console my deleted migration file timestamp is in this array. I would like to remove this version from the migrator. Also I cannot drop the database.
If the database can be blown away, then the quickest way would be to drop the database, create it afresh, and reapply the migrations, with the following steps:
rake db:drop
rake db:create db:migrate
If the database has useful information & can't be blown away, then it is tricky. Only possible option would be to go to the database level, and undo the changes made by the migration.
Figure out which tables/columns were added/deleted in the migration, and then run sql scripts to reverse those changes.
In addition, delete the specific row corresponding to this migration from schema_migrations table, with the following query:
delete from schema_migrations where version = '201503......'

My rails migrations won't run, and I can't deploy my rails app. How can I start over?

At some point in my rails development I started making database changes (e.g. dropping or altering columns/tables) without using rails migrations. So now I get errors when I try to deploy my rails app from scratch.
blaine#blaine-laptop ~/tmp/rbjacolyte $ rake db:migrate
(in /home/blaine/tmp/rbjacolyte)
== AddHashToTrack: migrating =================================================
-- add_column(:tracks, :hash, :string)
rake aborted!
An error has occurred, all later migrations canceled:
Mysql::Error: Table 'jacolyte_dev_tmp.tracks' doesn't exist: ALTER TABLE `tracks` ADD `hash` varchar(255)
(See full trace by running task with --trace)
How can I sync my production and development environments with migrations after I've mucked it up by using raw SQL? I want to deploy my rails application without database errors, and I don't want to start from scratch.
The data in the production and development environments match, but the migrations fail. I want a way to 'start from scratch.'
Could I simply delete all of the migrations that I have, and then just start using migrations from now on?
The shortcut way: manually add an entry to schema_migrations for a timestamp that represents a baseline. You can add migrations after that and as long as they don't make any bad assumptions about the db schema they should be able to run just fine. You won't be able to migrate backwards, but that's not a huge problem.
The bigger problem is that you won't be able to make a DB from scratch, which gets to be a pain longer term.
The fix for that is to delete all your existing migrations and create a new one that creates the existing schema. Manually delete everything from the schema_migrations table and put in an entry for this one new migration. After that, you can create new migrations that build on this new baseline and they should apply just fine. You should be able to bootstrap new databases in the normal fashion.
As long as your direct SQL is contained in Rails migrations, there's no problem with using it. Just make sure you implement both the #up and #down methods and you should be good. We've actually taken to using raw SQL as a best practice to avoid problems when models are changed later on. Something like
Foo.create(:name => 'bar')
seems innocuous, until the User model is modified to have
validates_presence_of :baz
At which point the new migration will run against an existing database, but that earlier migration that created the table and added the dummy entry will fail because User fails validation. Just using
execute("insert into foos (name) values ('bar')")
will work fine as long as the later migrations properly populate any new columns they add.
Maybe you could just get rid of all your current migrations, and use rake db:schema:dump to create a new schema.rb file, and manually edit your production database to reflect the changes you've made so far?
I like Veeti's suggestion, with a modification: rake db:schema:dump, then move that file to your development machine. Flatten your Rails migrations so far (see this SO thread on that), get rid of most of your migrations, and re-work your migrations to work, given your new schema.
Get this working on your dev machine, commit and deploy.
If the existing production data is compatible with the development database schema, then I would:
Dump the production data to a file using a program such as mysqldump
Drop the production database
Recreate the production database
Run the migrations against the production database, specifying VERSION=0
Import the production data from the file created at step one
If the schemas aren't compatible then you might be able to follow this process but you'll have to edit the SQL in the file created in the first step to take account of the schema differences.

How to rollback to beginning and recreate/rebuild new migrations

So this is my first real Ruby on Rails project. I've learned my lesson -- I didn't make all changes using migrations so things are a bit messed up.
What's the best way to start over with new migration files and rebuild the schema, etc? My project is too far along to rebuild the entire project, but not far enough along to where I care about losing the migrations I have thus far. I also don't mind losing the data in the database. I was trying to rollback to the beginning but some of it is failing.
I know this is a bad state to be in, but lesson learned.
EDIT:
I just deleted all the migrations files and rebuilt the schema file with db:schema:dump.
I assume this puts me in a clean state with my existing database, just lost migrations.
if you want to migrate some steps back you can
rake db:rollback STEP=2
That command will migrate your database 2 migrations back.
If you need more help with rake commands, jus type
rake -T
That command will list all the tasks you have in you application.
If you are not concerned about losing data then do
rake db:purge
It should just drop your database
Your schema.rb file should contain the actual schema from your database. You could use it as a starting point to create you migrations. You could create a new migration for each table with the :force => true parameter to overwrite the old table. Afterwards you could just delete the old migrations (you would probably also need to delete their entries from schema_migrations table).
Another options would be just updating the old migrations to match your current schema.

exactly what does rake db:migrate do?

Does rake db:migrate only add new migrations, or does it drop all migrations/changes and build everything new?
I think rake is throwing an error because it is trying to access a table attribute in migration 040 that was deleted in migration 042. somehow my DB and rake are out of synch and I want to fix them.
for you experts out there - is it common for rake to get out of synch with migrations? how can I avoid this (no, I do not hand-edit my schema or rake files).
When you use rails migrations, a table called schema_migrations is automatically created, which keeps track of what migrations have been applied, by storing the version number of each migration (this is the number that prefaces the migration name in the file name, ie db/migrate/_20090617111204__migration.rb). When you run rake db:migrate to migrate up, only migrations which have not been run previously (ie. their version is not contained in the table) will be run (for this reason, changing a migration that's already been executed will have no effect when running db:migrate). When migrating down, all versions found in schema_migrations that are greater than the version you are rolling back to will be undone.
Everytime you create a migration using scripts (like script/generate model ...) a new migration is added to the correct directory ready to be synched with the real database.
Actually rake db:migrate just checks which missing migrations still need to be applied to the database without caring about the previouse ones.
Of course if you modify the database using other ways is common to obtain out-of-synch things because as you said you can find yourself applying a migration to something that is changed underneath.
A migration means that you move from the current version to a newer version (as is said in the first answer). Using rake db:migrate you can apply any new changes to your schema. But if you want to rollback to a previous migration you can use rake db:rollback to nullify your new changes if they are incorrectly defined. Caution: by doing so your data will be lost.

Resources