Where is migration status saved? - ruby-on-rails

My question is very much related to this one Should I delete migration after rollback.
I had my original migrate file 20140731141350_create_users.rb
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email
t.string :password
t.timestamps
end
end
end
To which I needed to add a salt column, so I created the migration
20140804125449_add_salt_colum_to_users.rb
class AddSaltColumToUsers < ActiveRecord::Migration
def change
add_column :users, :salt, :string
end
end
But during development I realised the salt column wasn't necessary
and performed
rake db:migrate:down VERSION=20140731141350
Now I am left with an unused
20140804125449_add_salt_colum_to_users.rb migrate file.
My question is if I don't delete this migration file, where is this "down" status of this migration saved to? The migration file says add_column so if I run a db:migrate again how will it know that this specific file was migrated down?

db:migrate:down and db:rollback are similar. down reverts a database to a specified version, rollback - to the previous. To check is a migration applied Rails has a specific table called "schema_migrations" which stores timestamps of all applied migrations, so basically when you run db:migrate:down rails reverts the migration and remove the row from schema_migrations. So if you don't delete the migration file - rails will apply it in the next db:migrate

Related

Adding a column to an existing table

I used following code to add a field director to an existing movies table:
class CreateMovies < ActiveRecord::Migration
def up
create_table :movies do |t|
t.string :title
t.string :rating
t.text :description
t.datetime :release_date
# Add fields that let Rails automatically keep track
# of when movies are added or modified:
t.timestamps
end
add_column :movies, :director, :string
end
def down
drop_table :movies
end
end
I have already seen this, but the difrence is I am insisting to use
rake db:test:prepare command after i add my new field.
when i run rake db:test:prepare and then i run my cucumber, it gives me the erorr:
unknown attribute 'director' for Movie. (ActiveRecord::UnknownAttributeError)
this means that i failed to add the field director to the table movies,
So what is wrong here?
Try the following code:
rails g migration AddDirector
then, in the corresponding migration
def change
add_column :movies, :director, :string
end
Execute , rake db:migrate
In the Movies controller, add "director" in the movie_params
The db:test:prepare recreates the db using the db/schema.rb.
This will fix your issue:
bin/rake db:rollback
bin/rake db:migrate
When you do any migration, it gets saved in schema
Rollback that migration, make changes and then migrate it again
If for example 20150923000732_create_movies.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=20150923000732
After rollback your migration, change your migration file and migrate again.

Ruby on rails How to remove added columns and insert new columns through a migration file

HI I created a Ruby on rails migration file as follows and in the first stage I created tables
then I want to add columns and remove some columns and I modified it as follows
class CreateMt940Batches < ActiveRecord::Migration
def change
create_table :mt940_batches do |t|
t.string :account_number
t.string :transaction_reference_number
t.string :information_to_account_owner
t.string :file_name
t.binary :raw_data_transaction
t.string :sha1_checksum
t.timestamps
end
def self.down
remove_column :account_number, :transaction_reference_number, :information_to_account_owner
end
def self.up
add_column :mt940_batches, :created_by, :updated_by, :integer
end
end
end
but when I ran rake db:migrate nothing has happens. How to accomplish this task . I want to change the model already created as well from this migration file. Um looking a way to do this. Thank you in advance
You should add your remove / add column in a separate migration file.
class FooMigration < ActiveRecord::Migration
def down
remove_column :account_number, :transaction_reference_number, :information_to_account_owner
end
def up
add_column :mt940_batches, :created_by, :updated_by, :integer
end
end
Please note that your up and down method should be idem potent. You should be able to go from one to the other when calling rake db:migrate:down and rake db:migrate:up. This is not the case here.
However here, it seems that you want to achieve 2 different things in a single migration. If you want to add AND remove columns, consider moving each one in a different migration file:
Please read here for more details
You would end up with 2 migrations file like this:
class RemoveFieldsFromMt940Batches < ActiveRecord::Migration
def change
remove_column :mt940_batches, :account_number, :transaction_reference_number, :information_to_account_owner
end
end
class AddFieldsToMt940Batches < ActiveRecord::Migration
def change
add_column :mt940_batches, :created_by, :updated_by, :integer
end
end
Do not edit it if this migration already executed in production env create new one instead
if not you can use rake db:rollback, rollback migrations
Because this migration is already executed. you have to generate a new migration for adding and removing column in your table, i.e. you want to remove file_name from your table :
run this:
rails g migration RemoveFileNameFromCreateMt940Batches file_name:string
re-generate that column:
rails g migration AddFileNameToCreateMt940Batches file_name:string
Than run rake db:migrate it will remove column and add column again to your table.
Hope it will help. Thanks.
Create another migration file with removed column list
def change
remove_column :account_number, :transaction_reference_number, :information_to_account_owner
end
Create one migration file with added column list
def change
add_column :mt940_batches, :created_by, :updated_by, :integer
end
Do not alter the create table migration file. Other wise data saved in the file will be lost.
If data lost is not important for you, then just remove the table using rake db:migrate:down version=<your migration file version>
And change the migration file
then run
db:migrate:up version=<your migration file version>

One time change model attribute (column name) in Ruby on Rails

I created a model with an attribute "name" but I want to change it to "username". Everything I've read about database migrations involves creating a class or some complicated stuff. All I want to do is the equivalent of "UPDATE TABLE" in SQL. How do you run a one-time database migration to change this? I'm guessing it'd involve rails console and then some command?
First:
rails g migration rename_name_column_to_username
Then in the generated rename_name_column_to_username.rb migration file:
class RenameNameColumnToUsername < ActiveRecord::Migration
def self.up
rename_column :users, :name, :username
end
def self.down
rename_column :users, :username, :name
end
end
And then rake db:migrate
If you haven't committed the code that originally created the "name" column, you can just go in to the old migration file that created that column and change name to username and then regenerate the schema.
But if you have committed the code, you should create a separate migration file that renames name to username.
This is important to keep track of the versioning of your database. So you should never really use manual SQL (ALTER TABLE ...) to change the schema.
Run rails g migration RenameNameToUsername, which will create a new file in db/migrate.
Open that file, and add this into the self.up section:
rename_column :tablename, :name, :username
Then run rake db:migrate

Migration issue in Ruby-on-rails

Hey guys, when I first begin a rails project, the model user was designed and created. After all the migration part, it successful created the table "users" at postgres.
Well, then after doing some changes during the project, I realized that was missing an attribute/new column at the table.
So what I did was delete the table users from postgres and add a new column at my first migration ruby class:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.string :password
t.string :email
t.string :authorization_token //this is the new attribute that I insert
t.datetime :created_at
t.datetime :updated_at
t.timestamps
end
end
def self.down
drop_table :users
end
end
So, when I run again the db:migrate hopping that a new user table will be created with the new attribute :authorization_token, it doesn't work, but with no errors.
(I know that I should not remove the table, there is another smart way to do it)
A tip for working with Rails -- do not hand modify your tables using SQL. When you saw the problem you should have written a new migration like #nruth showed. Running the rake:migrate command would have worked fine for you.
In this case since you've already deleted your 'users' table you now have the problem that your database schema is out of sync with what Rails thinks it is. To fix this problem you can either get the database schema to roughly match what Rails thinks it is by hand creating the 'users' table, running the down migration and then then the up migration. Or you can get Rails up to speed with the fact that the 'users' table no longer exists. Rails stores migration info in either a schema_info table (Rails < 2.1) or schema_migrations table (Rails >= 2.1). If you remove that table then Rails will think the schema does not exist and try to run all the up migrations and recreate the 'users' table for you again.
Lastly, over time you may accumulate a number of migrations that individually add a column or two that you forgot to include. If you haven't yet shipped or aren't in production yet, then you can write a migration that sort of baselines your table. It would look something like this:
class CreateBaselineUsers < ActiveRecord::Migration
def self.up
create_table :users, :force => true do |t|
t.string :name
...
This will forcibly drop the table and recreate it with all the attributes that you want.
Migrations are run once & stored in the database as having been used (take a look in the schema_migrations table). You could try using rake db:migrate:reset to re-run your initial migration, but it's better to just add new migrations (you won't want to blow away your database when it has data in it) as follows:
script/generate migration add_authorization_token_to_users authorization_token:string
which will generate something similar to the following:
class AddAuthorizationTokenToUsers < ActiveRecord::Migration
def self.up
change_table :users do |t|
t.string :authorization_token //this is the new attribute that I insert
end
end
def self.down
remove_column :users, :authorization_token
end
end
To see how add/remove column, change_table, etc work, take a look at ActiveRecord::ConnectionAdapters::SchemaStatements at http://api.rubyonrails.org or http://guides.rubyonrails.org/migrations.html

How can I rename a database column in a Ruby on Rails migration?

I wrongly named a column hased_password instead of hashed_password.
How do I update the database schema, using migration to rename this column?
rename_column :table, :old_column, :new_column
You'll probably want to create a separate migration to do this. (Rename FixColumnName as you will.):
bin/rails generate migration FixColumnName
# creates db/migrate/xxxxxxxxxx_fix_column_name.rb
Then edit the migration to do your will:
# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
def self.up
rename_column :table_name, :old_column, :new_column
end
def self.down
# rename back if you need or do something else or do nothing
end
end
For Rails 3.1 use:
While, the up and down methods still apply, Rails 3.1 receives a change method that "knows how to migrate your database and reverse it when the migration is rolled back without the need to write a separate down method".
See "Active Record Migrations" for more information.
rails g migration FixColumnName
class FixColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
If you happen to have a whole bunch of columns to rename, or something that would have required repeating the table name over and over again:
rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...
You could use change_table to keep things a little neater:
class FixColumnNames < ActiveRecord::Migration
def change
change_table :table_name do |t|
t.rename :old_column1, :new_column1
t.rename :old_column2, :new_column2
...
end
end
end
Then just db:migrate as usual or however you go about your business.
For Rails 4:
While creating a Migration for renaming a column, Rails 4 generates a change method instead of up and down as mentioned in the above section. The generated change method is:
$ > rails g migration ChangeColumnName
which will create a migration file similar to:
class ChangeColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
In my opinion, in this case, it's better to use rake db:rollback, then edit your migration and again run rake db:migrate.
However, if you have data in the column you don't want to lose, then use rename_column.
If the column is already populated with data and live in production, I'd recommend a step by step approach, so as to avoid downtime in production while waiting for the migrations.
First I'd create a db migration to add columns with the new name(s) and populate them with the values from the old column name.
class AddCorrectColumnNames < ActiveRecord::Migration
def up
add_column :table, :correct_name_column_one, :string
add_column :table, :correct_name_column_two, :string
puts 'Updating correctly named columns'
execute "UPDATE table_name SET correct_name_column_one = old_name_column_one, correct_name_column_two = old_name_column_two"
end
end
def down
remove_column :table, :correct_name_column_one
remove_column :table, :correct_name_column_two
end
end
Then I'd commit just that change, and push the change into production.
git commit -m 'adding columns with correct name'
Then once the commit has been pushed into production, I'd run.
Production $ bundle exec rake db:migrate
Then I'd update all of the views/controllers that referenced the old column name to the new column name. Run through my test suite, and commit just those changes. (After making sure it was working locally and passing all tests first!)
git commit -m 'using correct column name instead of old stinky bad column name'
Then I'd push that commit to production.
At this point you can remove the original column without worrying about any sort of downtime associated with the migration itself.
class RemoveBadColumnNames < ActiveRecord::Migration
def up
remove_column :table, :old_name_column_one
remove_column :table, :old_name_column_two
end
def down
add_column :table, :old_name_column_one, :string
add_column :table, :old_name_column_two, :string
end
end
Then push this latest migration to production and run bundle exec rake db:migrate in the background.
I realize this is a bit more involved of a process, but I'd rather do this than have issues with my production migration.
See the "Available Transformations" section in the "Active Record Migrations" documentation.
rename_column(table_name, column_name, new_column_name):
Renames a column but keeps the type and content.
Run this command to create a migration file:
rails g migration ChangeHasedPasswordToHashedPassword
Then in the file generated in the db/migrate folder, write rename_column as below:
class ChangeOldColumnToNewColumn < ActiveRecord::Migration
def change
rename_column :table_name, :hased_password, :hashed_password
end
end
From the API:
rename_column(table_name, column_name, new_column_name)
This renames a column but keeps the type and content remains the same.
I had this challenge when working on a Rails 6 application with a PostgreSQL database.
Here's how I fixed it:
In my case the table_name was "Products", the old_column was "SKU" and the new_column was "ProductNumber".
Create a migration file that will contain the command for renaming the column:
rails generate migration RenameSKUToProductNumberInProducts
Open the migration file in the db/migrate directory:
db/migrate/20201028082344_rename_sku_to_product_number_in_products.rb
Add the command for renaming the column:
class RenameSkuToProductNumberInProducts < ActiveRecord::Migration[6.0]
def change
# rename_column :table_name, :old_column, :new_column
rename_column :products, :sku, :product_number
end
end
Save, and then run the migration command:
rails db:migrate
You can now confirm the renaming of the column by taking a look at the schema file:
db/schema.rb
If you are not satisfied with the renaming of the column, you can always rollback:
rails db:rollback
Note: Endeavour to modify the column name to the new name in all the places where it is called.
If your code is not shared with other one, then best option is to do just rake db:rollback
then edit your column name in migration and rake db:migrate. Thats it
And you can write another migration to rename the column
def change
rename_column :table_name, :old_name, :new_name
end
Thats it.
Some versions of Ruby on Rails support the up/down methods for migration and if you have an up/down method in your migration, then:
def up
rename_column :table_name, :column_old_name, :column_new_name
end
def down
rename_column :table_name, :column_new_name, :column_old_name
end
If you have the change method in your migration, then:
def change
rename_column :table_name, :column_old_name, :column_new_name
end
For more information see: Ruby on Rails - Migrations or Active Record Migrations.
As an alternative option, if you are not married to the idea of migrations, there is a compelling gem for ActiveRecord which will handle the name changes automatically for you, Datamapper style. All you do is change the column name in your model, and make sure you put Model.auto_upgrade! at the bottom of your model.rb, and viola! The database is updated on the fly.
See https://github.com/DAddYE/mini_record
Note: You will need to nuke db/schema.rb to prevent conflicts.
It is still in the beta phase and obviously not for everyone, but it is still a compelling choice. I am currently using it in two non-trivial production apps with no issues.
For Ruby on Rails 4:
def change
rename_column :table_name, :column_name_old, :column_name_new
end
If you need to switch column names you will need to create a placeholder to avoid a "duplicate column name" error. Here's an example:
class SwitchColumns < ActiveRecord::Migration
def change
rename_column :column_name, :x, :holder
rename_column :column_name, :y, :x
rename_column :column_name, :holder, :y
end
end
If the present data is not important for you, you can just take down your original migration using:
rake db:migrate:down VERSION='YOUR MIGRATION FILE VERSION HERE'
Without the quotes, then make changes in the original migration and run the up migration again by:
rake db:migrate
Simply create a new migration, and in a block, use rename_column as below.
rename_column :your_table_name, :hased_password, :hashed_password
Generate the migration file:
rails g migration FixName
which creates db/migrate/xxxxxxxxxx.rb.
Edit the migration to do your will:
class FixName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
Let's KISS. All it takes is three simple steps. The following works for Rails 5.2.
1 . Create a Migration
rails g migration RenameNameToFullNameInStudents
rails g RenameOldFieldToNewFieldInTableName - that way it is perfectly clear to maintainers of the code base later on. (use a plural for the table name).
2. Edit the migration
# I prefer to explicitly write theupanddownmethods.
# ./db/migrate/20190114045137_rename_name_to_full_name_in_students.rb
class RenameNameToFullNameInStudents < ActiveRecord::Migration[5.2]
def up
# rename_column :table_name, :old_column, :new_column
rename_column :students, :name, :full_name
end
def down
# Note that the columns are reversed
rename_column :students, :full_name, :name
end
end
3. Run your migrations
rake db:migrate
And you are off to the races!
Manually we can use the below method:
We can edit the migration manually like:
Open app/db/migrate/xxxxxxxxx_migration_file.rb
Update hased_password to hashed_password
Run the below command
$> rake db:migrate:down VERSION=xxxxxxxxx
Then it will remove your migration:
$> rake db:migrate:up VERSION=xxxxxxxxx
It will add your migration with the updated change.
Run rails g migration ChangesNameInUsers (or whatever you would like to name it)
Open the migration file that has just been generated, and add this line in the method (in between def change and end):
rename_column :table_name, :the_name_you_want_to_change, :the_new_name
Save the file, and run rake db:migrate in the console
Check out your schema.db in order to see if the name has actually changed in the database!
Hope this helps :)
def change
rename_column :table_name, :old_column_name, :new_column_name
end
Generate a Ruby on Rails migration:
$:> rails g migration Fixcolumnname
Insert code in the migration file (XXXXXfixcolumnname.rb):
class Fixcolumnname < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
$: rails g migration RenameHashedPasswordColumn
invoke active_record
create db/migrate/20160323054656_rename_hashed_password_column.rb
Open that migration file and modify that file as below(Do enter your original table_name)
class RenameHashedPasswordColumn < ActiveRecord::Migration
def change
rename_column :table_name, :hased_password, :hashed_password
end
end
In the console:
rails generate migration newMigration
In the newMigration file:
class FixColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
Open your Ruby on Rails console and enter:
ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column
You have two ways to do this:
In this type it automatically runs the reverse code of it, when rollback.
def change
rename_column :table_name, :old_column_name, :new_column_name
end
To this type, it runs the up method when rake db:migrate and runs the down method when rake db:rollback:
def self.up
rename_column :table_name, :old_column_name, :new_column_name
end
def self.down
rename_column :table_name,:new_column_name,:old_column_name
end
I'm on rails 5.2, and trying to rename a column on a devise User.
the rename_column bit worked for me, but the singular :table_name threw a "User table not found" error. Plural worked for me.
rails g RenameAgentinUser
Then change migration file to this:
rename_column :users, :agent?, :agent
Where :agent? is the old column name.
You can write a migration run the below command to update the column name:
rename_column :your_table_name, :hased_password, :hashed_password
Also, make sure that you update any usage of the old column name in your code with the new one.
A close cousin of create_table is change_table, used for changing existing tables. It is used in a similar fashion to create_table but the object yielded to the block knows more tricks. For example:
class ChangeBadColumnNames < ActiveRecord::Migration
def change
change_table :your_table_name do |t|
t.rename :old_column_name, :new_column_name
end
end
end
This way is more efficient if we use it with other alter methods such as: remove/add index/remove index/add column. We can do things like:
Rename
t.rename :old_column_name, :new_column_name
Add column
t.string :new_column
Remove column
t.remove :removing_column
Index column
t.index :indexing_column
rails g migration migrationName
So you go to your generated migration and add:
rename_column :table, :old_column, :new_column
to the method
First you need to run
rails g migration create_new_column_in_tablename new_column:datatype
rails g migration remove_column_in_tablename old_column:datatype
and then you need to check db/migration
you can check the details in the nem migration, if all the details is correct you need to run:
rails db:migrate
Just generate the migration using:
rails g migration rename_hased_password
After that edit the migration and add the following line in the change method:
rename_column :table, :hased_password, :hashed_password
This should do the trick.

Resources