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.
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
How do I create a new field in an existing table using the Ruby command prompt?
I created the model (and migrated it) but I forgot to add a field - how would I go about this?
Generate a new migration to add a new column to table.
rails g migration add_column_name_to_table_name column_name:type
This will create a migration class like below:
#config/migration/20150304121554_add_column_name_to_table_name.rb
class AddColumnNameToTableName < ActiveRecord::Migration
def change
add_column :table_name, :column_name, :type
end
end
Here, column_name, table_name and type should be your desired name and type. Than run rake db:migrate command.
There are two ways to make changes in your situation:
Roll back the last migration
Add the new field in a new migration
Undoing the last migration should only be done if you have not yet pushed the migration to a public server. Here's how to do it:
Run rake db:rollback
Add the new field to the same migration file you originally used
Run rake db:migrate
Option 2:
To add the field in a new migration:
rails g migration AddFieldNameToTableName
For example, if your field is name and your table is users, you would run:
rails g migration AddNameToUsers
This will create a new migration file whose name starts with today's date and ends with add_name_to_users.rb. Open the file and add the field using the add_column command, like this:
class AddNameToUsers < ActiveRecord::Migration
def change
add_column :users, :name, :string
end
end
Save the file, then run rake db:migrate.
I encourage you to read the Rails migrations guide to learn more.
I have migration (created way back) that i need to change, it's the below:
20130923000732_create_questions.rb
I need to change
t.string to --> t.text
how can i achieve this ?
I read along that i can create a new migration renaming the column, but i did not quite understand it.
If 20130923000732_create_questions.rb migration is your last migration you can rollback with:
rake db:rollback
Otherwise you can simply down your specific migration with VERSION:
rake db:migrate:down VERSION=20130923000732
After rollback your migration, change your migration file and migrate again.
Your app is in development yet, just open that migration in edtor, change it to text and run all your migrations again.
Or write a migration that will update that field type.
First in you terminal:
rails g migration change_column_type_in_questions
Then in your migration file:
class ChangeColumnTypeInQuestions < ActiveRecord::Migration
def change
change_column :questions, :body, :text
end
end
Migration will look for table questions and will update column body type without loosing data.
Run rails generate migration change_string_to_text_in_questions then a new migration file will be created, with
def change
end
method, now insert, change_column :table_name, :column_name, :type now your migration file should look like this,
def change
change_column :table_name, :column_name,:type
end
After this, Save the Changes and run db:migrate
What's the syntax for dropping a database table column through a Rails migration?
remove_column :table_name, :column_name
For instance:
remove_column :users, :hobby
would remove the hobby Column from the users table.
For older versions of Rails
ruby script/generate migration RemoveFieldNameFromTableName field_name:datatype
For Rails 3 and up
rails generate migration RemoveFieldNameFromTableName field_name:datatype
Rails 4 has been updated, so the change method can be used in the migration to drop a column and the migration will successfully rollback. Please read the following warning for Rails 3 applications:
Rails 3 Warning
Please note that when you use this command:
rails generate migration RemoveFieldNameFromTableName field_name:datatype
The generated migration will look something like this:
def up
remove_column :table_name, :field_name
end
def down
add_column :table_name, :field_name, :datatype
end
Make sure to not use the change method when removing columns from a database table (example of what you don't want in the migration file in Rails 3 apps):
def change
remove_column :table_name, :field_name
end
The change method in Rails 3 is not smart when it comes to remove_column, so you will not be able to rollback this migration.
In a rails4 app it is possible to use the change method also for removing columns. The third param is the data_type and in the optional forth you can give options. It is a bit hidden in the section 'Available transformations' on the documentation .
class RemoveFieldFromTableName < ActiveRecord::Migration
def change
remove_column :table_name, :field_name, :data_type, {}
end
end
There are two good ways to do this:
remove_column
You can simply use remove_column, like so:
remove_column :users, :first_name
This is fine if you only need to make a single change to your schema.
change_table block
You can also do this using a change_table block, like so:
change_table :users do |t|
t.remove :first_name
end
I prefer this as I find it more legible, and you can make several changes at once.
Here's the full list of supported change_table methods:
http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/change_table
Clear & Simple Instructions for Rails 5 & 6
WARNING: You will lose data.
Warning: the below instructions are for trivial migrations. For complex migrations with e.g. millions of rows, read/write dbs, clusters, this advice is not for you:
1. Create a migration
Run the following command in your terminal:
rails generate migration remove_fieldname_from_tablename fieldname:fieldtype (Table name in plural, as per convention. See the documentation here. )
Example: rails g migration RemoveAcceptedFromQuotes accepted:boolean
2. Check the migration
# db/migrate/20190122035000_remove_accepted_from_quotes.rb
class RemoveAcceptedFromQuotes < ActiveRecord::Migration[5.2]
# with rails 5.2 you don't need to add a separate "up" and "down" method.
def change
remove_column :quotes, :accepted, :boolean
end
end
3. Run the migration
rake db:migrate or rails db:migrate (they're both the same)
....And then you're off to the races!
Generate a migration to remove a column such that if it is migrated (rake db:migrate), it should drop the column. And it should add column back if this migration is rollbacked (rake db:rollback).
The syntax:
remove_column :table_name, :column_name, :type
Removes column, also adds column back if migration is rollbacked.
Example:
remove_column :users, :last_name, :string
Note: If you skip the data_type, the migration will remove the column successfully but if you rollback the migration it will throw an error.
in rails 5 you can use this command in the terminal:
rails generate migration remove_COLUMNNAME_from_TABLENAME COLUMNNAME:DATATYPE
for example to remove the column access_level(string) from table users:
rails generate migration remove_access_level_from_users access_level:string
and then run:
rake db:migrate
Remove Columns For RAILS 5 App
rails g migration Remove<Anything>From<TableName> [columnName:type]
Command above generate a migration file inside db/migrate directory. Snippet blow is one of remove column from table example generated by Rails generator,
class RemoveAgeFromUsers < ActiveRecord::Migration
def up
remove_column :users, :age
end
def down
add_column :users, :age, :integer
end
end
I also made a quick reference guide for Rails which can be found at here.
You can try the following:
remove_column :table_name, :column_name
(Official documentation)
rails g migration RemoveXColumnFromY column_name:data_type
X = column name
Y = table name
EDIT
Changed RemoveXColumnToY to RemoveXColumnFromY as per comments - provides more clarity for what the migration is actually doing.
To remove the column from table you have to run following migration:
rails g migration remove_column_name_from_table_name column_name:data_type
Then run command:
rake db:migrate
remove_column in change method will help you to delete the column from the table.
class RemoveColumn < ActiveRecord::Migration
def change
remove_column :table_name, :column_name, :data_type
end
end
Go on this link for complete reference : http://guides.rubyonrails.org/active_record_migrations.html
For removing column from table in just easy 3 steps as follows:
write this command
rails g migration remove_column_from_table_name
after running this command in terminal one file created by this name and time stamp (remove_column from_table_name).
Then go to this file.
inside file you have to write
remove_column :table_name, :column_name
Finally go to the console and then do
rake db:migrate
Give below command it will add in migration file on its own
rails g migration RemoveColumnFromModel
After running above command you can check migration file remove_column code must be added there on its own
Then migrate the db
rake db:migrate
Heres one more from rails console
ActiveRecord::Migration.remove_column(:table_name, :column_name)
Step 1: Create a migration
rails g migration remove_column_name_from_table
Step 2: Change code in file migration just created
rails version < 3
def change
remove_column :table_name, :column_name, :datatype
end
rails version >= 3
def change
remove_column :table_name, :column_name
end
Step 3: Migrate
rake db:migrate
Simply, You can remove column
remove_column :table_name, :column_name
For Example,
remove_column :posts, :comment
first try to create a migration file running the command:
rails g migration RemoveAgeFromUsers age:string
and then on the root directory of the project run the migration running the command:
rails db:migrate
Through
remove_column :table_name, :column_name
in a migration file
You can remove a column directly in a rails console by typing:
ActiveRecord::Base.remove_column :table_name, :column_name
Do like this;
rails g migration RemoveColumnNameFromTables column_name:type
I.e. rails g migration RemoveTitleFromPosts title:string
Anyway, Would be better to consider about downtime as well since the ActiveRecord caches database columns at runtime so if you drop a column, it might cause exceptions until your app reboots.
Ref: Strong migration
Mark the column as ignored in the model
class MyModel < ApplicationRecord
self.ignored_columns = ["my_field"]
end
Generate a migration
$ bin/rails g migration DropMyFieldFromMyModel
Edit the migration
class DropMyFieldFromMyModel < ActiveRecord::Migration[6.1]
def change
safety_assured { remove_column :my_table, :my_field }
end
end
Run the migration
$ bin/rails db:migrate
you can use rails migration command
rails generate migration RemoveColumnNameFromTableName column_name:column_type
than you can migrate the database:
rails db:migrate
Just run this in the rails console
ActiveRecord::Base.connection.remove_column("table_name", :column_name, :its_data_type)
or
TableName.find_by_sql(“ALTER TABLE table_name DROP column_name”)