database migration in rails3.1 - ruby-on-rails-3

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.

Related

Why can't I use MySQL 'year' data type in my Rails App?

According to MySQL reference manual there is a data type as "year". I wanted to use it with my rails app but when i run rails db:migrate , it fails and says :
NoMethodError: undefined method `year' for #<ActiveRecord::ConnectionAdapters::MySQL::TableDefinition:0x000056047e3c6120>
Create_book migration file:
class CreateBooks < ActiveRecord::Migration[5.2]
def change
create_table :books do |t|
t.string :name
t.year :release
t.references :genre, foreign_key: true
t.references :author, foreign_key: true
t.timestamps
end
end
end
If you are using DateTime then t.datetime will work for you.
If you are storing year only, it can be stored in integer, use t.integer which will simply store year. Maybe mysql have datatype year but here your ruby object for mysql connection adapter do not have.

Why do I keep getting an error that there's a duplicate field in my Table when it's not true?

I am attempting to use Paperclip in my Ruby on Rails project but I keep getting this error in my Terminal:
SQLite3::SQLException: duplicate column name: image_file_name: ALTER TABLE "orders" ADD "image_file_name"
I get this right after I type in rake db:migrate with a migration file that looks like this:
class AddAttachmentImageToOrders < ActiveRecord::Migration
def self.up
change_table :orders do |t|
t.attachment :image
end
end
def self.down
drop_attached_file :orders, :image
end
end
However, my schema file looks like this:
create_table "orders", force: true do |t|
t.integer "transaction_id"
t.datetime "created_at"
t.boolean "shipped"
t.datetime "updated_at"
t.text "name"
t.text "email_address"
t.text "address_1"
t.text "address_2"
t.text "city"
t.text "state"
t.integer "zip"
t.string "size"
end
I'm sure there's something I'm missing. If it's not seeing the duplicate in the schema, where is it seeing it?
Your problem is your database already has those columns
Paperclip uses t.attachment to input these columns to your db:
[attachment]_file_name
[attachment]_content_type
[attachment]_file_size
[attachment]_updated_at
Your t.attachment basically means you're trying to create one of these columns, but they already exist. The way to fix this is to just get rid of the contents of that migration, run rake db:migrate again, then delete the file

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

Adding a column to an existing table in a Rails migration

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.