I have associations set up in survey model as follows
attr_accessible :name, :questions_attributes
has_many :questions
and in question model
attr_accessible :content, :survey_id, :answers_attributes
belongs_to :survey
I have a migration that adds question_id to survey table
but I came to realise that this migration wouldn't be necessary as
I have already defined their associations in the model.
Is my understanding correct?
If my understanding is correct, I would like to reverse that migration.
I have added the last 2 lines starting with remove and ran rake db:migrate
but it doesn't do anything.
def change
add_column :surveys, :question_id, :integer
add_index :surveys, :question_id
remove_column :surveys, :question_id, :integer
remove_index :surveys, :question_id
end
def up
add_column :surveys, :question_id, :integer
add_index :surveys, :question_id
end
def down
remove_index :surveys, :question_id
remove_column :surveys, :question_id
end
The up method is executed on rake db:migrate, the down method is executed on rake db:rollback
You cannot rely only on the change method, because of the order in which the rollback needs to be done(first remove index, then remove column)
edit:
Actually, you can do it with just change in Rails 3.2+
def change
add_column :surveys, :question_id, :integer
add_index :surveys, :question_id
end
As per my understanding you want to rollback the migration. If so then you can use the below syntax for that
rake db:rollback STEP=n
or
rake db:migrate:down VERSION=<version_number_of_migration>
which rollsback the particular migration
Yes its always neccessary to write a migration to add question_id in survey table
Only Declaring Associations is not enough
Your migrtaion should like this
def change
add_reference :surveys,:question ,index : true
end
At any point rollback the migration if you have changes only in your system. Dont try to rollback once these migrations are ran in different environments
To rollback rake db:migrate:rollback VERSION="timestamp of migration file"
Related
I have a migration file called [timestamp]_create_posts.rb.
I found that I made the column with a wrong data type. I need to make t.text :content instead of t.string :content.
I include the code from the above file:
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.string :content
t.timestamps null: false
end
end
end
I kinda know that I should not directly change the file but rollback migration and change the schema and do the migration again. But I wasn't sure whether that's a right way to do it. It would be really nice if someone can guide me through this. I'm not really familiar with Rails.
You should not rollback anything. You should create a new migration, that will change a column with following content:
class UpdatePostsChangeContentColumn < ActiveRecord::Migration
def change
change_column :posts, :content, :text, limit: 60000 # or whatever
end
end
or, even better, to supply the reasonable rollback of this migration:
class UpdatePostsChangeContentColumn < ActiveRecord::Migration
def up
change_column :posts, :content, :text, limit: 60000 # or whatever
end
# back to previous version
def down
change_column :posts, :content, :string
end
end
The other option if you are just in the development is just to Drop you database and recreate it. Then you can modify that file, but THIS IS NOT ADVISED. I have done this again in development where i didn't care about recreating my database
rake db:drop
rake db:create
rake db:migrate
There are two ways to change the column in table:
You can use rake db:rollback VERSION=file_version and then after that you can change datatype manually.
Generate another migration file. e.g rails g migration RemoveColumnToPost and the you can add following codes:
def up
change_column :posts, :content, :text
end
def down
change_column :posts, :content, :string
end
And then use rake db:migrate
I read RoR guide and I don't understand the next line:
If you wish for a migration to do something that Active Record doesn't know how to reverse, you can use reversible
What does it mean "doesn't know how to reverse"? How to distinguish what Active Record can reverse and what cannot?
It's simply, there are two kinds of operations in AR migrations:
1) Rails automatically knows how to rollback (revert) those operations in migrations, for example:
def change
add_column :users, :age, :integer
end
migration means add column age, rollback means remove column age. Or create_table, reverse operation is drop_table. This operations you can put into change method in migration and rails knows what to do when rollback / reverse those migrations.
2) Rails needs to help how to process migration and rollback process, usually it is operations which somehow modifies data.
def self.up
add_column :users, :name, :string
add_column :users, :surname, :string
say_with_time 'Split username into name and surname' do
Users.select(:username).all.each do |user|
user.name = user.username.split(/ /)[0]
user.surname = user.username.split(/ /)[1]
user.save!
end
end
remove_column :users, :username
end
As you can see, this operation is quite complicated. Rails does not know how to reverse this operation, so you have to write reverse operation code in self.down:
def self.down
add_column :users, :username, :string
say_with_time 'Join name and surname into username' do
User.all.each do |user|
user.update_attributes(username: "#{user.name} #{user.surname}")
end
end
remove_column :users, :name
remove_column :users, :surname
end
and thats all...
My User_ID miration says interger not integer.
class AddUserIdToPins < ActiveRecord::Migration
def change
add_column :pins, :user_id, :interger
add_index :pins, :user_id
end
end
I'm assuming I just can't change it from "interger" to "integer" using my text editor because it should be in my tables too.
Here is the way :
(A) First grab the specific migration number:
[shreyas#Arup-iMac rails_app_test (master)]$ rake db:migrate:status
database: app_development
Status Migration ID Migration Name
--------------------------------------------------
up 20150219075735 Create people
up 20150219085131 Add likes to persons
up 20150219114058 Add email to people
[shreyas#Arup-iMac rails_app_test (master)]$
(B) Now suppose, you want to edit the migration , 20150219085131, then do :
bin/rake db:migrate:down VERSION=20150219085131
(C) Then edit your migration and fix what you want to fix :
class AddUserIdToPins < ActiveRecord::Migration
def change
add_column :pins, :user_id, :integer
add_index :pins, :user_id
end
end
(D) And finally, again :
rake db:migrate:up VERSION=20150219085131
And you are done!
And If you are not able to run the current migration, then no worry, just change the file content by hand, and run rake db:migrate.
Edit your migration like this:
class AddUserIdToPins < ActiveRecord::Migration
def up
add_reference :pins, :user, index: true
end
def down
remove_index :pins, :user_id
remove_column :pins, :user_id
end
end
You rollback that migration:
bin/rake db:migrate:down VERSION=version_number
And try again:
bin/rake db:migrate:up VERSION=version_number
You can change it to :integer and then you have to run the migration, which will put the column in your db-tables:
rake db:migrate
If you try to run the migration like this it should show an error like:
type "interger" does not exist
Hi I have got a rails migration problem:
When I run a migration 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 do a rake db:migrate it works fine. The columns are renamed and the data of those columns is in there. But when I then do a rake db:drop, create, migrate the columns are renamed and the data of those columns is gone... (One of my migration files fills the data base and it also fills those two columns before they get renamed)
What's the problem here?
Another question: I know its not a good idea to change former migration files, but is that ok when I run rake db:drop db:create and db:migrate afterwards - or will that cause problems?
The order of my migration files is the following:
add_devise_to_users -> creates a table users
add_columns_to_default_user -> adds columns and updates the whole table
class AddColumnsToDefaultUser < ActiveRecord::Migration
def change
add_column :users, :name, :string
add_column :users, :dob, :date
add_column :users, :address, :string
add_column :users, :hotel_stars, :integer
add_column :users, :restaurant_stars, :integer
add_column :users, :profile_picture_url, :string
add_column :users, :selected_car, :integer
User.reset_column_information
User.find(1).update_attributes!( :name => 'Alexander MacDonald', :dob => '1984-08-20', :address => '900 Highschool Way, Mountain View, CA 94041', :hotel_stars => '3', :restaurant_stars => '2', :profile_picture_url => 'user1.png', :selected_car => 1)
end
end
and then rename_column
class RenameColumn < ActiveRecord::Migration
def change
rename_column :users, :hotel_stars, :rating_stars
rename_column :users, :restaurant_stars, :price_stars
end
end
When you do db:drop you're erasing your DB.
So, when you do that the data is wiped. That data isn't going into a temporary place to be re-inserted. If you want to retain the data that's in the DB before/after a db:drop you need to store it somewhere and re-insert it yourself.
When you're changing structure only, unless you have a specific reason to remove the data that's in there already, all you need to do is the db:migrate.
Alternatively you can use something like populator in order to empty/fill you DB with test data following a migration.
Im trying to set up my app to work with authlogic.. the thing is, other than the fields authlogic is supposed to use I want to keep in my database other attributes
Like Name, Last Name, PIN, etc... is there a way to do this?
You say "keep" - do you mean you have an existing database of users and you want to keep this info as you migrate to AuthLogic, or do you mean you just want to store this additional info?
Either way is possible but I'm going to assume you mean that you just want to store additional information - all you have to do is script/generate migration AddFieldsToUser then edit the migration:
class AddFieldsToUser < ActiveRecord::Migration
def self.up
add_column :users, :name, :string
add_column :users, :last_name, :string
add_column :users, :pin, :integer
end
def self.down
remove_column :users, :name
remove_column :users, :last_name
remove_column :users, :pin
end
end
Then run rake db:migrate