Adding a column to an existing table in a Rails migration - ruby-on-rails-3

I have a Users model which needs an :email column (I forgot to add that column during the initial scaffold).
I opened the migration file and added t.string :email, did rake db:migrate, and got a NoMethodError. Then I added the line
add_column :users, :email, :string
again rake db:migrate, again NoMethodError. Am I missing a step here?
Edit: here's the migration file.
class CreateUsers < ActiveRecord::Migration
def self.up
add_column :users, :email, :string
create_table :users do |t|
t.string :username
t.string :email
t.string :crypted_password
t.string :password_salt
t.string :persistence_token
t.timestamps
end
end
def self.down
drop_table :users
end
end

If you have already run your original migration (before editing it), then you need to generate a new migration (rails generate migration add_email_to_users email:string will do the trick).
It will create a migration file containing line:
add_column :users, email, string
Then do a rake db:migrate and it'll run the new migration, creating the new column.
If you have not yet run the original migration you can just edit it, like you're trying to do. Your migration code is almost perfect: you just need to remove the add_column line completely (that code is trying to add a column to a table, before the table has been created, and your table creation code has already been updated to include a t.string :email anyway).

Use this command on the terminal:
rails generate migration add_fieldname_to_tablename fieldname:string
and
rake db:migrate
to run this migration

Sometimes rails generate migration add_email_to_users email:string produces a migration like this
class AddEmailToUsers < ActiveRecord::Migration[5.0]
def change
end
end
In that case you have to manually an add_column to change:
class AddEmailToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :email, :string
end
end
And then run rake db:migrate

You can also do
rake db:rollback
if you have not added any data to the tables.Then edit the migration file by adding the email column to it and then call
rake db:migrate
This will work if you have rails 3.1 onwards installed in your system.
Much simpler way of doing it is change let the change in migration file be as it is.
use
$rake db:migrate:redo
This will roll back the last migration and migrate it again.

To add a column I just had to follow these steps :
rails generate migration add_fieldname_to_tablename fieldname:string
Alternative
rails generate migration addFieldnameToTablename
Once the migration is generated, then edit the migration and define all the attributes you want that column added to have.
Note: Table names in Rails are always plural (to match DB conventions). Example using one of the steps mentioned previously-
rails generate migration addEmailToUsers
rake db:migrate
Or
You can change the schema in from db/schema.rb, Add the columns you want in the SQL query.
Run this command: rake db:schema:load
Warning/Note
Bear in mind that, running rake db:schema:load automatically wipes all data in your tables.

You can also add column to a specific position using before column or after column like:
rails generate migration add_dob_to_customer dob:date
The migration file will generate the following code except after: :email. you need to add after: :email or before: :email
class AddDobToCustomer < ActiveRecord::Migration[5.2]
def change
add_column :customers, :dob, :date, after: :email
end
end

You also can use special change_table method in the migration for adding new columns:
change_table(:users) do |t|
t.column :email, :string
end

When I've done this, rather than fiddling the original migration, I create a new one with just the add column in the up section and a drop column in the down section.
You can change the original and rerun it if you migrate down between, but in this case I think that's made a migration that won't work properly.
As currently posted, you're adding the column and then creating the table.
If you change the order it might work. Or, as you're modifying an existing migration, just add it to the create table instead of doing a separate add column.

You can also do this ..
rails g migration add_column_to_users email:string
then rake db:migrate
also add :email attribute in your user controller ;
for more detail check out http://guides.rubyonrails.org/active_record_migrations.html

You can also force to table columns in table using force: true, if you table is already exist.
example:
ActiveRecord::Schema.define(version: 20080906171750) do
create_table "authors", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
end

You could rollback the last migration by
rake db:rollback STEP=1
or rollback this specific migration by
rake db:migrate:down VERSION=<YYYYMMDDHHMMSS>
and edit the file, then run rake db:mirgate again.

Related

Rails removing a column from activerecord not working

I want to remove container:references from my table, I have tried:
rails generate migration RemoveContainerfromCreateTasks container:references
followed by rails db:migrate, but it my reference field is still not removed.
Below is my ActiveRecord
class CreateTasks < ActiveRecord::Migration[6.1]
def change
create_table :tasks do |t|
t.string :title
t.text :body
t.references :container, null: false, foreign_key: true
t.text :tag
t.datetime :due
t.integer :priority
t.timestamps
end
end
end
class RemoveContainerfromCreateTasks < ActiveRecod::Migration[6.1]
def change
end
end
The issue here is really a sneaky capitalization error. Running:
rails generate migration RemoveContainerfromCreateTasks container:references
Will generate a migration with an empty change block which will do absolutely nothing when you migrate it except modify the migrations meta table (a table that AR uses to keep track of which migrations have been run). But if you properly capitalize From:
rails generate migration RemoveContainerFromCreateTasks container:references
It will generate:
class RemoveContainerFromCreateTasks < ActiveRecord::Migration[6.0]
def change
remove_reference :create_tasks, :container, null: false, foreign_key: true
end
end
Rails isn't actually intelligent. It just casts the name argument into snake case and compares it to a set of patterns like:
remove_something_from_tablename foo:string bar:integer
create_tablename foo:string bar:integer
create_foo_bar_join_table foo bar
And it then uses a template to generate the according type of migration. If you don't properly pluralize it will be cast into:
remove_containerfrom_create_tasks
Which Rails does not know what to do with as it does not match a known pattern.
Also note despite popular belief migrations are just a DSL to create SQL transformations which is completely unaware about your tables or models. In this case the resulting migration will just blow up when you attempt to run it since you don't have a create_tasks table.
I would roll the missnamed migration back. Delete it then run:
rails g migration RemoveContainerFromTasks container:references
rails db:migrate
Your issue here is that "CreateTasks" is not table in your database. "Tasks" is, however.
rails g migration RemoveContainerFromTasks container:references
will provide you
class RemoveContainerFromTasks < ActiveRecord::Migration[6.1]
def change
remove_reference :tasks, :container, null: false, foreign_key: true
end
end
A migration of this will successfully remove container from your schema.rb file, and subsequently the database system you're using.
Here's some console output, because why not:
unclecid#home:~/Desktop/sample_app$ rails db:migrate
== 20201227150512 CreateTasks: migrating ======================================
-- create_table(:tasks)
-> 0.0022s
== 20201227150512 CreateTasks: migrated (0.0023s) =============================
== 20201227151021 RemoveContainerFromTasks: migrating =========================
-- remove_reference(:tasks, :container, {:null=>false, :foreign_key=>true})
-> 0.0330s
== 20201227151021 RemoveContainerFromTasks: migrated (0.0331s) ================

Will renaming Rails migration files affect my live app?

I edited to contents of some of my migration files to solve an issue between Paperclip and an Attachment model, renaming it to Upload.
01234_create_attachments.rb
class CreateAttachments < ActiveRecord::Migration
def change
create_table :attachments do |t|
t.string :name
t.string :attachment_url
t.timestamps
end
end
end
became this:
01234_create_attachments.rb
class CreateUploads < ActiveRecord::Migration
def change
create_table :uploads do |t|
t.string :name
t.string :upload_url
t.timestamps
end
end
end
Note that I only edited the file contents, not the file name.
The existing app runs fine but now I can't git clone the repo to a new server because rake db:migrate fails. If I then edit the actual migration filenames on the new server it runs properly:
01234_create_attachments.rb > 01234_create_uploads.rb
My question is if I rename the migration files in my master branch will it cause problems with my existing live app when I rake db:migrate in the future?
Your file name and class name of migration should match.
schema_migrations table is used to determine if the migration should run or not. Since that table only has timestamp, unless you change the timestamp, it wouldn't rerun the migration.
Its not advised to change existing migration after it has been run on production environment. Add a new migration if you have to change anything.

Migration file updated not reflect in Schema.rb file

I am running a migration like this:
class CreatePages < ActiveRecord::Migration
def change
create_table :pages do |t|
t.string :name
t.string :permalink
t.integer :position
t.boolean :visible
t.timestamps
end
end
end
And then I figure I forgot to set the default value for the boolean, so I go back to the migration file and add the following:
t.boolean :visible, :default => false
I then run the rake db:migrate again. However, the schema.rb file does not update. I had run the migration before for quite awhile so it is not possible to rollback and redo the migration.
I know that I should not update the Schema file directly.
Anyone can help me to make the schema.rb file to update according to what I have change in the migration file.
Thank you
You have to add new migration to change default value for the column.
See this post

RoR: how can I add columns to my database on my live heroku app?

I am trying to add :price, :location, and :product to the columns for my microposts table. I have already done a bunch of other migrations and I have heard that rolling back all of migrations and redoing them is error prone. So I guess the other option is the schema file? I have heard that the schema file is just to be read and not edited. I have been looking at http://guides.rubyonrails.org/migrations.html but can't find the right info. They briefly talk about change_table which I think could be useful but it doesn't go into depth. Is this what I am looking for?
Just create a new standalone migration:
rails g migration add_price_location_and_product_to_microposts
It will create a file in the db/migrate folder, edit it:
def change
add_column :microposts, :price, :float # dont forget to change the type to the columns
add_column :microposts, :location, :string
add_column :microposts, :product, :integer
end
(You can define the change method, instead of up and down because add_column is a reversible command.)
And then, run rake db:migrate

database migration in rails3.1

Recently I got a question about rails3.1's migration.Here is the one of the migration file code.
def change
create_table :books do |t|
t.string :title
t.decimal :price
end
end
Now I need to add a foreign key, let's say comment_id, I used to create another migration and use add_column method in it to get it done.
But since we are in rail3.1,so I thought there might be a new way to do it.so I alter the code
def change
create_table :books do |t|
t.string :title
t.decimal :price
t.references :comment
end
end
OK,now I run rake db:migrate and nothing happens. Any idea?
did you run rake db:rollback before running rake db:migrate? You need to roll back the migration before reapplying it with the changes.