rake:db rollback does not delete the migration? - ruby-on-rails

I have entrees and snapshots. An entree has_many snapshots. I forgot to add the foreign key to snapshots. So I later added migration:
$ rails generate migration add_snapshot_ref_to_entrees snapshot:references
Migration file looked like this:
class AddSnapshotRefToEntrees < ActiveRecord::Migration[5.0]
def change
add_reference :entrees, :snapshot, foreign_key: true
end
end
This did not do what I want. It added an snapshot_id to entrees, rather than adding an entree_id to snapshots.
So I run the rollback:
bundle exec rake db:rollback
It correctly moves the following from schema.rb:
add_foreign_key "entrees", "snapshots"
And also correctly rolls back the database itself. But the migration file remains in db/migrate. Am I suppose to remove this myself or did not complete its job?

Yes, you need to remove this file manually. Regarding your association, it should be as below:
class AddSnapshotRefToEntrees < ActiveRecord::Migration[5.0]
def change
add_reference :snapshots, :entree, foreign_key: true
end
end

It's not supposed to.
rails destroy migration add_snapshot_ref_to_entrees

In order to rollback a specific migration use:
rake db:migrate:down VERSION=YOUR_MIGRATION_VERSION
For Example:
rake db:migrate:down VERSION=20100905201547
To find the version of all migrations, you can use this command:
rake db:migrate:status

rake db:migrate:down and rollback worked on database label it's not removing file from db/migrate.
You need to remove direct from db/migrate folder.

Related

rails migration is not reflecting while migration is successful

I have created 2 tables (categories and products) and I did has_many association like Category has_many :products and Product belongs_to :category.
When I do a migration like:
rails generate migration add_product_id_to_categories product_id:integer
then migration is running but not seeing product_id in Category.
I've tried multiple ways like
add_product_id_to_category product_id:integer
but still facing the same problem.
You only generated a migration file (rails generate migration add_product_id_to_categories product_id:integer). You have to run the migration with rake db:migrate.
Generating a migration is a different thing than actually running it. You just generated it, and in order to execute what you have written, you need to run it, and you can do so by invoking the following command:
rake db:migrate
Not sure that either you have run the migration or not, run the following command, and it will tell you the statues of all the migrations. If the status is up, the migration has been run, and for down, a migration couldn't be run.
rake db:migrate:status
When you run a migration, and you would like to get notified in terminal that it has been successfully run, you can add a puts statement in there like following:
class AddColumnToCategories < ActiveRecord::Migration
def change
add_column :categories, :product_id, :integer, index: true
puts "product_id column has been added into categories."
end
end
Have you tried rails generate migration AddProductIdToCategories product_id:integer?
When you have created the migration if you look inside the migration file you can see if any code has been generated in the change method before you run the migration. If it has not generated any content you can manually add it:
def change
add_column :categories, :product_id, :integer
end

Fixing migration error

I tried to create a migration to add roles to my user tables but i accidentally typed AddRolesToUsers instead of AddRoleToUser. So i tried creating a new migration with the correct AddRoleToUsers but when i tried to run rake db:migrate i got an error :
SQLite3::SQLException: duplicate column name: role: ALTER TABLE "users" ADD "role" integer/Users/miguel/.rvm/gems/ruby-2.2.1/gems/sqlite3-1.3.11/lib/sqlite3/database.rb:91:in `initialize'
I tried rake db:migrate:down VERSION= do delete the one I had to type on but i keep getting the same error . PS: i deleted the migration file manually after running rake db:migrate:down VERSION=
rails g migration AddRoleToUsers role:integer
migration file :
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :integer
end
end
When you ran the first migration, the role column was added to the Users table. The error on the second migration tells you that much.
To clear the migration pending error, you need to comment out the add_column statement in the new migration.
i.e,
class AddRoleToUsers < ActiveRecord::Migration
def change
# add_column :users, :role, :integer
end
end
Then run the migration. This way, the new migration should run successfully.
You can now uncomment it and delete the previous migration, so that when you deploy, only the newer migration is run and the role column is added successfully.
In that case right click and delete both migration files and start again. The error exists because it thinks you want to add two columns both named role to your users table
UPDATE
In that case, if role already exists in your users table, a migration must've been successfully run and there is no need to run another. As long as the role column is there, trying to add another column called role will always give you an error. If you wanted to test that you are still able to add new columns you can always check by creating a test migration AddSomethingToUsers something:string and rake db:migrate to test, then rake db:rollback to undo..but it all seems like it's worked so I probably my wouldn't mess with it too much.

Irreversible migration, can it be fixed? - Rails 4

So i made a migration like this
class AddDatetimeAttrToUsers < ActiveRecord::Migration
def change
change_column :users, :oauth_expires_at, :datetime
end
end
on my local environment it works just fine but when i try
heroku run rake db:migrate i get an error
ERROR: column "oauth_expires_at" cannot be cast automatically to type timestamp without time zone
HINT: Specify a USING expression to perform the conversion.
When i searched it, i created a new migration like this as best practice for changing an attribute using change.
class PutDatetimeFieldToUsersExpireAtColumn < ActiveRecord::Migration
def change
remove_column :users, :oauth_expires_at
add_column :users, :oauth_expires_at, :datetime
end
end
so i tried to use rake db:rollback to delete last migration and add this one informing me that the last migration is irreversible.
my question is, is there a way to actually rollback on an irreversible migration or should i just migrate using the new migration above?
In your example, you have the following migration file:
class AddDatetimeAttrToUsers < ActiveRecord::Migration
def change
change_column :users, :oauth_expires_at, :datetime
end
end
You have already run rake db:migrate successfully in your dev environment. You are running sqlite3 locally and PG on heroku, and and as a result, your change_column works locally, but it fails on PG because PG expects a 'using' statement.
The fix this, step 1 is to edit your migration file to add an up and down migration as suggested by Yohann above. Yes, you should do this even though you have already raked this migration.
class AddDatetimeAttrToUsers < ActiveRecord::Migration
def up
change_column :users, :oauth_expires_at, :datetime
end
def down
change_column :users, :oauth_expires_at, :time (or whatever type existed before datetime)
end
end
Now you can run rake db:rollback and avoid the irreversible migration error, but only if you HAVE NOT ADDED ADDITIONAL MIGRATIONS. If you have added additional migrations you will need to specify how far back to go using rake db:down VERSION=2018xxxxxxx or rake db:rollback STEP=X.
Now edit the migration so it plays nice with pg and sqlite3:
class AddDatetimeAttrToUsers < ActiveRecord::Migration
def up
change_column :users, :oauth_expires_at, :datetime, using: 'oauth_expires_at::datetime'
end
def down
change_column :users, :oauth_expires_at, :time
end
Now you should be able to rake db:migrate, push to heroku, and heroku run rake db:migrate and move on.
Finally, you should get pg working locally to match your production environment.
You can define up and down methods instead of change in your migration.
Here is an example:
def up
connection.execute %(create or replace view name_of_the_db_view)
end
def down
connection.execute %(drop view name_of_the_db_view)
end
With it you will be able to migrate and rollback the previously irreversible migration like it was a normal migration.
It seems you need to specify a current type of oauth_expires_at column, because at rollback Rails should know it to create the column. I mean following:
remove_column :users, :oauth_expires_at, :string
if you dare to lose your data on your local database then you can recover from irreversible migration(by losing your database data) by doing these steps:
1- first deleting your database(assuming that you are in the development environment and just ok to delete the database in this environment - your test database will also be gone)
export RAILS_ENV=development
rake db:drop
2- Reloading your schema file:
rake db:schema:load
3- To see your current migration files:
rake db:migrate:status
4- Delete the migration that you want to get rid of:
rake db:migrate:down VERSION=xxxxxx
rails destroy migration migration_name
5- Then you can make db:migrate to migrate your migrations.
rake db:migrate

Schema file does not reflect table removal migrations

I removed several tables in my Rails database by running rails generate migration RemoveObjects and then ran rake db:migrate to complete the migration, however I am not seeing the change reflected in my schema.rb file.
What else should I do to remove references to these object from that file?
Try this :
rake db:schema:dump
This migration will! You probably made a mistake inside the migration itself.
class DropTables < ActiveRecord::Migration
def up
drop_table :table_name
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

Rails migrations after database reset

Hi I have a general migration problem:
When I create migrations like this:
class RenameColumn < ActiveRecord::Migration
def change
rename_column :users, :hotel_stars, :rating_stars
rename_column :users, :restaurant_stars, :price_stars
end
end
and change the code in the Model-,View- and Controller file accordingly(I dont create new Model etc.):
ie.
Model: attr_accessible :rating_stars, :price_stars
(instead of :hotel_stars, :restaurant_stars )
Controller: #rating = current_user.rating_stars
When I now run the migration (rake db:migrate) -> it works!
But after a rake db:drop, rake db:create, rake db:migrate it doesn't anymore!
What is wrong with this migration? How can you create migrations that are working WITH and WITHOUT resetting the database?
Thanks!!
I think your issue is that rake db:create does not rebuild your database from schema.rb. For that you need to do rake db:setup instead of rake db:create. In any case I would try rake db:reset instead of drop/create as I believe that will accomplish what you want to do in one step.
Type rake -T for a list of available tasks and what they do.
Also see here for more information on rails migrations:
http://guides.rubyonrails.org/migrations.html
Did you ever manually alter the state of your database and/or modify a migration after it was run? If so, you messed up the state of migrations.
You "could" alleviate this by adding a migration that gets your database where your new migration expects it to be, or you could fix the migration that was altered before.
Depending on how many other developers you have, I would go for the latter in this case.

Resources