schema.rb not getting updated on rake db:rollback - ruby-on-rails

I have multiple branches each with a migration file. So when I checkout a branch, I do a db:migrate and it would in turn update my schema.rb file.
But, when I checkout another branch and run rake db:migrate, Ideally the changes made my the migration in the previous branch should be removed from schema.rb and the details of the new migration should get into schema.rb
This doesn't happen.
So, I did a rake db:rollback STEP=5, when I checked out a new branch and then did a db:migrate. Even now, I have table details of the migration in previous branch. What I am I doing wrong ? Or is this how Rails behaves?

All performed migrations are saved in table schema_migrations (migration timestamp is saved in DB). When you run rake db:migrate Rails parses directory db/migrate and finds files which are not presented in the table (it compares by timestamp).
Let's you have you have 10 migrations in branch master - schema_migrations has 10 records with timestamps. You create a new branch from master branch_1, create and run there a new migration. Your table schema_migrations has 11 records.
You go back to master and run rake db:migrate - Rails will do NOTHING because no new files are found (in db/migrate). When you run rake db:rollback STEP=5 I suppose (I have never checked it) Rails rollback 5 last migrations from branch MASTER. And it's logical because the last migration (made in branch_1) doesn't exist in branch master (the file with code exists only in branch_1!). So you can't rollback DB changes made in branch_1 from branch master.
What todo?!
I see several strategies:
1) checkout to branch_1 and run rake db:rollback STEP=N (N >= count of new migrations) (You can rollback more migrations then you performed in this branch). Checkout back to master and run rake db:migrate (to perform migrations from master)
2) when you have production dump or good seeds.
Drop current DB, load dump (or seeds), run rake db:migrate
(As for me it is the simplest way when you have production dump!)
PS Maybe smbd else suggest other way to get correct DB in current branch

Related

How to solve Rails merge conflicts with db/structure.sql

I was told that I should follow the below steps if make new migrations in my branch and have merge conflicts with master in the db/structure.sql file.
In the branch, bundle exec rake db:drop
In the branch, bundle exec rake db:create
In master, bundle exec rake db:structure:load
In the branch, git merge master
In the branch, bundle exec rake db:migrate
What are steps 1-3 necessary if all I want to do is align the db/structure.sql file? By merging in master, don't I get the new migrations I haven't ran yet and then by running them, it will update my db/structure.sql?
You're right, dropping and recreating the database to solve a conflict in db/structure.sql (or db/schema.rb for that matter) is a little ridiculous. You should be able to simply run the new migrations and get an updated structure.sql from the db:migrate.
The db/stucture.sql file is simply the database's structure as the database sees it (whereas db/schema.rb is the database's structure in the limited view of it that ActiveRecord has). If there is a conflict in structure.sql, that simply means:
The merge involves new migrations which change the database structure.
The branch you're merging in has run the migrations in a different order so the schema's don't quite match up even though they may be functionally equivalent.
(1) is solved by running the new migrations and possibly fixing any places where the migrations themselves are in conflict. A quick bin/rake db:migrate should fix this and leave you with a new non-conflicted db/structure.sql.
(2) is solved the same way. You could also do a a manual bin/rake db:structure:dump to rebuild db/structure.sql but you'd only do this if you're certain that you really do have this situation; but really, db:migrate will take care of it so there's no reason not to just db:migrate.
Conflicts in db/structure.sql (or db/schema.rb) don't indicate a problem with the db/structure.sql itself, they indicate problems with the database that git can't directly see. The solution to the conflicts is to fix the database.
You can just run bundle exec rake db:structure:dump to re-generate the db/structure.sql file.
For schema.rb I found https://stackoverflow.com/a/3815807/6003161

Rails destroy migration/model on Heroku

Image I created a migration on rails development then I pushed to Heroku;
rails g migration add_smth_to_payments smth:string
rake db:migrate
git add -A
git commit -am "migration smth to payments"
git push heroku master
Then I wanted to destroy this migration again starting from development then push to Heroku;
rake db:rollback
rails d migration add_smth_to_payments
git add -A
git commit -am "destroy migration smth to payments"
git push heroku master
Now, my question is, after destroying the migration (could be model as well), does heroku remove this migration from payments table? I am asking because destroying takes place development
Thank you
Once a migration has been run, the migration file itself is irrelevant. You can delete it, edit it, rename it (as long as the timestamp prefix is left alone) and nothing will happen to the database. In fact, many people periodically delete old migrations to avoid cluttering db/migrate with irrelevant noise.
If you need to undo a migration (i.e. "remove this migration from payments table") then you either write a new migration to undo it or rollback your migrations. Rolling back isn't always an option though: some migrations cannot be reversed and rolling back can reverse migrations you don't want reversed.
All this applies to production/Heroku, development, and anywhere else that you db:migrate.

Rails: How to delete a pending migration

I'm currently following the ruby on rails tutorial: http://guides.rubyonrails.org/getting_started.html.
I am trying to save data into the database. However, when I run: rails server I get the following error:
Migrations are pending. To resolve this issue, run: bin/rake db:migrate RAILS_ENV=development
I've looked at the other articles and when I run:
bin/rake db:migrate
I get a rake aborted!
After running:
rake db:abort_if_pending_migrations....
I see that:
You have 1 pending migration:
20150805200129 CreateDatabases
SQLite3::SQLException: table "databases" already exists:
and it just tells me to run rake db:migrate to start again.
It seems that it already exists. Is there a way to cancel the pending migration?
Sometimes, even dropping a local development database is not a good idea.
There are better ways to delete/destroy a specific migration in your Rails application.
You could use rails d migration command to destroy a particular migration:
rails d migration MigrationName
To undo the changes corresponding to a particular migration, you can use db:migrate:down method like this:
rake db:migrate:down VERSION=XXX
Sometimes, things could get more messy and in those situation another handy thing is to take a look at the schema_migrations table in your database which has all the migrations with their version saved in it.
You can delete a particular migration from this table like this:
delete from schema_migrations WHERE version = VERSION;
if you don't want that migration to be present anymore.
Your migration may have failed midway (so it created the table, but didn't finish).
You are just using development environment, so it's okay to just drop the database and rebuild it from scratch:
rake db:drop # THIS WILL DELETE YOUR DATABASE
rake db:create
rake db:migrate
If you are like me and maintain your database structure outside of Rails, you can just delete the migration file from db/migration. I got the error in the OP's question when I used the rails generate command to create a model class, forgetting that it also creates a migration file.
Do not use this method if you rely on Rails to maintain your database structure!
I keep my Rails structure file up to date by building it from the database using:
bundle exec rake db:structure:dump
I do not encourage to drop the database and start from the beginning especially when you already have the data inside the database.
My approach to this will be migrate first, then rollback. After that you can safely delete the migration file. So the procedure is as following.
rails db:migrate
rails db rollback
rm db/migrate/your_last_migration_file.rb
You can recreate database and run all migrations in your development environment with such command
rails db:migrate:reset
If you want to revert the wrong migrations, You can drop the whole db using this:
rake db:drop
Then remove the migrations file manually(This wont corrupt the db when you recreate as the Schema migrations would be dropped as well).
Then run
rake db:migrate
And if there is data to be seeded, then run this as well
rake db:setup

Managing conflict in schema.rb created by Git operation

I created a migration, ran rake db:migrate, which bumped my db/schema.rb version number. Then I did a git fetch origin master and saw that there were changes from my team members. So I did a git stash and a git rebase FETCH_HEAD, followed by a git stash pop. This resulted in a conflict in db/schema.rb over the version number.
Upstream>>>
ActiveRecord::Schema.define(:version => 20110930179257) do
===========
ActiveRecord::Schema.define(:version => 20110930161932) do
<<<Stashed
I think the appropriate fix would be to manually increment the version number to something higher than the upstream.
Is this sensible, or bad news?
Thanks,
Max
If your current database has the correct schema, you should:
Run pending migrations (if any)
rake db:migrate
Overwrite your schema.rb from your current database schema
rake db:schema:dump
And commit
When I find myself with this conflict, I simply migrate the database. Whether there are pending migrations or not, the conflict will be corrected.
tldr
Accept the Upstream version and run rake db:migrate as you'd normally do.
why is that the way to go
Don't worry about the migrations you've created (which are below Upstream version 20110930179257). ActiveRecord uses a table schema_migrations where it puts all of the migrations that have been run. If your migrations aren't on the list but in db/migrate directory, then ActiveRecord will run them.
Here's the table so you can visualise it better:
It's tempting to think that it's actually this line:
ActiveRecord::Schema.define(:version => 20110930179257)
that defines latest migration run, so no migrations with version below it are going to be run. This is fortunately not true. Rails will run any migrations that are in db/migrate folder and not yet in the schema_migrations table.
According to this answer, a conflict is guaranteed. The user has to to manually merge, and set the version as the higher of the two.
Here's what I do when merging master into my feature branch fails over conflicts in db/schema.rb:
$ git merge --abort
$ git checkout master
$ rake db:drop db:create db:migrate
$ git checkout -- db/schema.rb
$ git checkout my_feature_branch
$ rake db:migrate
$ git add db/schema.rb
$ git commit -m 'Updated schema'
$ git merge master
~/bin/update-schema-rb:
#!/usr/bin/env bash
git co master
bin/rake db:reset db:seed
git co -
bin/rake db:migrate
An option is to have a manual version script which is additive only. There you want conflicts. Schema is something that will bite you hard if you don't keep on top of it. So once bitten, twice shy, I don't mind keeping schema and lookup info (list of customer types) with an additive only change management scheme.
I feel the best approach is to do rake db:drop db:create db:migrate to regenerate schema using migrations that exist only on the current branch. That way migrations from other branches won't leak into your schema file and give you headache later - in case if you switch branches a lot.

How can I rollback a specific migration?

I have the migration file db\migrate\20100905201547_create_blocks.rb.
How can I specifically rollback that migration file?
rake db:rollback STEP=1
Is a way to do this, if the migration you want to rollback is the last one applied. You can substitute 1 for however many migrations you want to go back.
For example:
rake db:rollback STEP=5
Will also rollback all the migration that happened later (4, 3, 2 and also 1).
To roll back all migrations back to (and including) a target migration, use: (This corrected command was added after all the comments pointing out the error in the original post)
rake db:migrate VERSION=20100905201547
In order to rollback only one specific migration (out of order) use:
rake db:migrate:down VERSION=20100905201547
Note that this will NOT rollback any interceding migrations -- only the one listed. If that is not what you intended, you can safely run rake db:migrate and it will re-run only that one, skipping any others that were not previously rolled back.
And if you ever want to migrate a single migration out of order, there is also its inverse db:migrate:up:
rake db:migrate:up VERSION=20100905201547
rake db:migrate:down VERSION=20100905201547
will roll back the specific file.
To find the version of all migrations, you can use this command:
rake db:migrate:status
Or, simply the prefix of the migration's file name is the version you need to rollback.
See the Ruby on Rails guide entry on migrations.
To rollback the last migration you can do:
rake db:rollback
If you want to rollback a specific migration with a version, you should do:
rake db:migrate:down VERSION=YOUR_MIGRATION_VERSION
For example, if the version is 20141201122027, you will do
rake db:migrate:down VERSION=20141201122027
to rollback that specific migration.
You can rollback your migration by using rake db:rollback with different options. The syntax will be different according to your requirements.
If you want to rollback just the last migration, then you can use either
rake db:rollback
or
rake db:rollback STEP=1
If you want rollback number of migrations at once, then you simply pass an argument:
rake db:rollback STEP=n
where n is number of migrations to rollback, counting from latest migration.
If you want to rollback to a specific migration, then you should pass the version of the migration in the following:
rake db:migrate:down VERSION=xxxxx
where xxxxx is the version number of the migration.
Use:
rake db:migrate:down VERSION=your_migrations's_version_number_here
The version is the numerical prefix on the migration's file name.
How to find the version:
Your migration files are stored in your rails_root/db/migrate directory. Find the appropriate file up to which you want to rollback and copy the prefix number.
For example:
File name: 20140208031131_create_roles.rb
Then the version is 20140208031131.
Rolling back the last migration:
# rails < 5.0
rake db:rollback
# rails >= 5.0
rake db:rollback
# or
rails db:rollback
Rolling back the last n number of migrations
# rails < 5.0
rake db:rollback STEP=2
# rails >= 5.0
rake db:rollback STEP=2
# or
rails db:rollback STEP=2
Rolling back a specific migration
# rails < 5.0
rake db:migrate:down VERSION=20100905201547
# rails >= 5.0
rake db:migrate:down VERSION=20100905201547
# or
rails db:migrate:down VERSION=20100905201547
To rollback the last migration you can do:
rake db:rollback
If you want to rollback a specific migration with a version you should do:
rake db:migrate:down VERSION=YOUR_MIGRATION_VERSION
If the migration file you want to rollback was called db/migrate/20141201122027_create_some_table.rb, then the VERSION for that migration is 20141201122027, which is the timestamp of when that migration was created, and the command to roll back that migration would be:
rake db:migrate:down VERSION=20141201122027
To roll back all migrations up to a particular version (e.g. 20181002222222), use:
rake db:migrate VERSION=20181002222222
(Note that this uses db:migrate -- not db:migrate:down as in other answers to this question.)
Assuming the specified migration version is older than the current version, this will roll back all migrations up to, but not including, the specified version.
For example, if rake db:migrate:status initially displays:
(... some older migrations ...)
up 20181001002039 Some migration description
up 20181002222222 Some migration description
up 20181003171932 Some migration description
up 20181004211151 Some migration description
up 20181005151403 Some migration description
Running:
rake db:migrate VERSION=20181002222222
Will result in:
(... some older migrations ...)
up 20181001002039 Some migration description
up 20181002222222 Some migration description
down 20181003171932 Some migration description
down 20181004211151 Some migration description
down 20181005151403 Some migration description
Reference: Migrate or revert only some migrations
If it is a reversible migration and the last one which has been executed, then run rake db:rollback. And you can always use the version.
For example, if the migration file is 20140716084539_create_customer_stats.rb, the rollback command will be:
rake db:migrate:down VERSION=20140716084539
If you are using Ruby on Rails 3
Step: 1 (check the last migration)
bundle exec rake db:migrate:status
Step: 2 (roll back the last migration)
bundle exec rake db:rollback
Now, you can revert the migration with safety one by one.
For a specific migration
rails d migration <migration_name>
For reverting multiple migrations
bundle exec rake db:rollback STEP=n
where n is how many migrations you want to rollback.
Example: bundle exec rake db:rollback STEP=5
A migration file looks like this,
20221213051020_my_migrations
In this case, the model name should be MyMigration. The migration ends with a plural word, so it ends with migrations.
To roll back this particular migration, you have to understand that the first part of the migration name (number in front of the migration name) is the migration number.
To roll back this migration, just open the terminal and write,
rake db:migrate:down VERSION=migration_number
So finally, you have to actually type in the terminal to roll back this particular migration,
Write the below command on terminal to rollback a particular migration, upper command is just to explain you
rake db:migrate:down VERSION=20221213051020
Just remember that each migration has a different migration number, so watch carefully and copy paste or type manually.
Migrations change the state of the database using the command
bundle exec rake db:migrate
We can undo a single migration step using
bundle exec rake db:rollback
To go all the way back to the beginning, we can use
bundle exec rake db:migrate VERSION=0
As you might guess, substituting any other number for 0 migrates to that version number, where the version numbers come from listing the migrations sequentially.
Well, in rails 5 it's quite easy
rake db:migrate:status
or
rails db:migrate:status
It was modified to handle both the same way.
Then just pick which version you want to roll back
and then run
rake db:migrate VERSION=2013424230423
Make sure VERSION is all capital letters.
If you have a problem with any step of the migration or stuck in the middle simply, go to the migration file and comment out the lines that were already migrated.
If you want to rollback and migrate you can run:
rake db:migrate:redo
That's the same as:
rake db:rollback
rake db:migrate
I found these steps most useful.
To check for status, run rails db:migrate:status. Then you'll have a good view of the migrations you want to remove.
Then, run rails db:rollback to revert the changes one by one. After doing so, you can check the status again to be fully confident.
Next, if you want to remove or delete. Run rails d migration <migration_name>. This would clean up the versions you created.
After that's done, you can proceed to making new changes.
For a multiple databases configurations (RoR >= v6), you must append the database name in the command, like:
rails db:rollback:primary, where primary is the name of the database in your config/databases.yml file, to roll back the last migration. You can make usage of the STEPS attribute here, as usual.
rails db:migrate:down:primary VERSION=your_migration_timestamp, to revert only the provided migration version. Here primary is the name of the database too.
In addition:
When a migration you deployed long ago does not let you migrate a new one.
I work in a larger Ruby on Rails application with more than a thousand of migration files. And, it takes a month for us to ship a medium-sized feature. I was working on a feature and I had deployed a migration a month ago, and then in the review process the structure of migration and filename changed, now I try to deploy my new code, the build failed saying:
ActiveRecord::StatementInvalid: PG::DuplicateColumn: ERROR: column "my_new_field" of relation "accounts" already exists
None of the above-mentioned solutions worked for me, because the old migration file was missing and the field I intended to create in my new migration file already existed in the database. The only solution that worked for me is:
I scped the file to the server
I opened the rails console
I required the file in the IRB session
then AddNewMyNewFieldToAccounts.new.down
And then I could run the deploy build again.
You can run down migration command to rollback the migration like below:
rake db:migrate:down VERSION=20100905201547
If you want to revert from the last migration, use the rake db:rollback command. It's working fine for me!

Resources