ruby migration rolled back but get error when run migration again - ruby-on-rails

This is the error I get when running a migration in a RoR application:
PG::Error: ERROR: column "bulk_bill" of relation "questionnaires" already exists
A little background:
I rolled back a migration so that I could change the default setting for a column.
Once I ran the migration again I got the error above.
I can see in the postgresql table in development that the column does exist. I have a data in the tables and in the bulk_bill column it has it's default set to false.
What are the recommended steps I need to take so that I so the migration can be run successfully.
I am a beginner in ruby and find the ruby documentation still a little hard to follow.
def up
add_column :questionnaires, :bulk_bill, :boolean, :default => false
end
def down
remove_column :pnp_questionnaires, :bulk_bill
end

In your up method you're creating column on questionaries table, and in your down method you are removing it from pnp_questionaries. Remove column does not raise an excepton if table doesn't exists, hence you have your problem.
Simplest solution:
Comment out add_column from up.
Run migrations (yes, run empty migration).
Fix your down method to remove questionaries table.
Rollback migration.
Uncomment your up method.
UPDATE:
My bad - point 3 was to be 'remove column from questionaries', not 'remove table'.
You need to rerun the migration which created the table (hopefuly you didn't alter it in a meantime). Go to the given migration, comment out down method body, and run rake db:migrate:redo VERSION=xxxxxxx where xxxxxx is the timestamp in this migration filename.

Related

Why can I no longer rake db:migrate when adding new columns to my table? Can I add columns manually in the migration file or should I generate one?

Good morning everyone,
I am trying to complete the calender app from Codeacademy, and I need to complete the following steps.
Open the migration file in db/migrate/ for the days table, and add the following columns:
a datetime column called date
Open the migration file in db/migrate/ for the days table, and add the following columns:
a datetime column called date
Open the migration file in db/migrate/ for events tracks table, and add the following columns:
a string column called name
a datetime column called from
a datetime column called to
a string column called location
a references column to the Day model
So far, I have added it manually to the migration files like so:
class CreateDays < ActiveRecord::Migration
def change
create_table :days do |t|
t.datetime :date
t.timestamps
end
end
end
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.string :name
t.datetime :from
t.datetime :to
t.string :location
t.timestamps
#Not sure how to add references column????
end
end
end
However, I am running into an error when I run rake db:migrate, I get no output. Is there supposed to be an output? I have run rake db:migrate --trace and here is the output:
A migration file is like a script which changes your database in some way. It does not store the state of your database.
It will not do anything unless you run it: your database has a special table to keep track of which ones have been run already, called schema_migrations. When you do rake db:migrate you run all scripts in that folder which haven't been run already, according to that table.
So, if you run a script, then change it, then do db:migrate, it won't run it again because it thinks it's been run already. If it did run it again, it would likely blow up because it would be trying to add lots of columns that already exist.
If you define a table in a migration, then later want to add more columns, you can either roll the migration back (which will drop the table), then run it again with the added columns, or write a new migration which just adds the required new columns. The latter approach is usually best.
Whenever you run rake db:migrate,it runs all the pending migrations using the timestamp which every migration file has ..such as YYYYMMDDHHMMSS_create_products.rb.
Any file which has a migrations greater than the previously run migration timestamp will be picked up during rake db:migrate and then checked whether the changes are present in the db.
For example :
For a migration file 20080906120001_add_details_to_products.rb...if you have ran it then all the changes will be added in the db.if you edit it and then run it again then it won't be picked up as timestamp of migration should be grater then previously ran file,which is not.
You can manually change the migrations by editing few numbers so that it gets picked up again without creating a new file.
I would recommend create a new one as they are way to maintain and are each migration should be unique.
I assume that you have ran the migrations before. So there is a table named schema_migrations where it stores the migration which has already ran so you cannot re run them. The best way to add new columns to an existing table is to create a new migration like this:
rails g migration add_some_columns_to_events name:string
and name the other columns. And still if you need to do it using the existing migration then what you can do is:
rake db:migrate:down VERSION=<version_of_migration>
and then add up the columns in migration file and run:
rake db:migrate:up VERSION=<version_of_migration>
You can also rollback your last migration and re run the migration using:
rake db:rollback
Hope this helps.
You can only run a migration once - if you've already run the migration, you have two options:
You can roll back the migration with rake db:rollback, edit it, and then run it again with rake db:migrate, or
You can generate a new migration and put your changes in it. Then you can run the new migration with rake db:migrate.

adding a new column in a rails database migration

So I've been going through a lot of rails tutorial, and I get that the default for adding a new column to a database is , for example,
rails generate migration add_reset_to_users reset_digest:string reset_sent_at:datetime
The above will add a reset_digest in the form of a string and reset_sent_at in the form of a date to the migration add_reset_to_users
My questions is what if I am clumsy one night at 4 AM and only call the following
rails generate migration add_reset_to_users reset_digest:string
I completely forgot about reset_sent_at but want to implement it the next morning. I made the mistake of adding the link directly to the db file, which was a huge mistake.
In this case what should I do? Do I simply call a new migration such as
rails generate migration add_reset_sent_to_users reset_sent_at:datetime
or is there an even better way?
first, if you have not run your migration, you can directly open the migration file, and add your column to the file, as
def change
add columns :table_name :column_name :column_type
end
In your case, you will modify the file as,
def change
add columns :users :reset_digest :string
add columns :users :reset_sent_at :datetime
end
and then run
rake db:migrate
if you have already ran your migration, and you have not run any other migration after that, you can undo it, by
rake db:rollback STEP=1
and then edit the migration file, and run your migration
Rule of thumb for migrations in Rails is that you always create a new migration file unless you have not already shared your code with others, i.e. pushed to remote repository, otherwise you can just change the old migration after running $ rake db:rollback and everything will be fine, and nobody will know about it, and won't affect other developers work(since it's still on your local repository).
So, I'd encourage you to create a new migration if you have already committed and pushed the code onto remote repository, and changing the old migration file again will hurt other developers productivity. In case of any confusion, always create a new migration:
rails generate migration add_reset_sent_to_users reset_sent_at:datetime
I think it depends what state your rails app is in.
If you were working on a production app then editing migrations is not advisable due to data loss and changes should be made with a new migration.
If your working locally in development then I would edit the migration directly and add the missing column and rerun your migration.
Don't be worried about editing you migrations, just remember to rake db:rollback the migration you are editing before making changes or you will encounter errors.
This is where changing your migration from:
def change
add_column('users', 'reset_digest', :string)
add_column('users', 'reset_sent_at', :datetime) # Would have to perform rollback before adding this line
end
to:
def up
add_column('users', 'reset_digest', :string)
add_column('users', 'reset_sent_at', :datetime) # Added after migration
**rake db:migrate
end
def down
remove_column('users', 'reset_digest', :string)
remove_column('users', 'reset_sent_at', :datetime) # Add this after rollback
**rake db:rollback
end
Allows you to make changes to your migrations before you rake db:rollback
This requires a bit more code but I find it easier when I'm building a new app and things are changing frequently.

Rails Migration Successful, But Not Showing up in Model?

I can't figure out why my migration worked but doesn't show up in corresponding model...
Ran a migration to add field to a table:
def up
add_column :quick_tests, :trace_route_data, :text, :null => true
end
def down
remove_column :quick_tests, :trace_route_data
end
Looked in schema.rb, and it's there.
Added :trace_route_data to attr_accessible in QuickTest model
Opened up rails console by doing bundle exec rails c, ran QuickTest.new and I can see the :trace_route_data field.
But, when I execute the same QuickTest.new statement when paused in the QuickTestController#show method, the field isn't there.
Why is this field showing up in the rails console but not my actual app??
I suspect something went wrong during the migration such that it never got applied to the database. Rails uses the actual schema in the database to build model objects, so the fact that your model doesn't show the change means the change is almost certainly not in the database (despite being in the schema.rb).
I'd recommend you rollback your migration and run it again in verbose mode. This should either show you the error, or at least show you the SQL being run. In that case, you can run the SQL manually at the db console and see what happens then.

Fixing error in deleted migration and table

I'm trying to update my heroku database. The problem: I created an old model & table that we no longer need. That table had previously been migrated to a production server (along with other changes). I did a destroy of the model using:
rails destroy model ReallyLongModelName
That also deleted the migration that created the table.
Later, I created a migration to drop that table.
class Drop_ReallyLongTableName < ActiveRecord::Migration
def change
drop_table :really_long_table_name
end
end
I'm now getting a couple of errors.
First error:
When trying to migrate the database to the production version of the application, I get this error.
Input string is longer than NAMEDATALEN-1 (63)
I'm not sure how to go back and edit the name to avoid the long name, so that it clears
Second error:
When trying to rollback the Drop_ReallyLongTableName migration, its aborts the rake because
rake aborted!
An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: no such table: really_long_table_name
Does anyone have any ideas on how to solve this? Thanks!
Have you tried running this from your Terminal/console:
heroku run console
ActiveRecord::Migration.drop_table(:table_name)
The migration is the way to go but this might be worth a try to see if the table even exists any more (since your second error message seems to indicate that it is no longer there).
Also, and for what it's worth, you can add conditional logic to your DB migrations should you need to in the future
def change
drop_table :table_name if self.table_exists?("table_name")
end

How do I add a new attribute to a migration in Rails 3?

Here's my story: I had something like this set up a while ago.
create_table(:users) do |t|
t.database_authenticatable :null => false
t.recoverable
t.rememberable
t.trackable
t.integer :total_pageviews
and "total_pageviews" worked fine. I could set it to zero, increment it, multiply it, call it, whatever. but let's say i want to add:
t.integer :total_votes
What do I have to do to configure total_votes as an attribute? Whenever I try to use "total_votes", I get undefined method error. I'm thinking that the answer is something like rake db:migrate or similar.
You should not ever alter existing migrations. If you have checked them in to your version control system and somebody else runs them and then you add a new field to them and commit that change, they will not know to get that change. Then you must tell them and it's a pain in the butt to fix.
If you've not committed it yet then rollback the migration (rake db:rollback), make the necessary modification and re-run it again (rake db:migrate).
But in the Real World, you would create a new migration which adds this field using rails g migration add_total_votes_to_users total_votes:integer.
Rails will interpret this migration name and know what to do with it, generating a migration that contains this line:
add_column :users, :total_votes, :integer
Then when you run this migration it will add this total_votes field to the users table which will make an attribute of the same name for all User objects.
Are you adding this after the migration has been run? So, the users table exists and you want to add a column to it? If so, you need go create a migration like
rails generate migration add_total_votes_to_users
Open it up (just to verify that the table and column are correct). Then run the migration.
If you app is in production, then you should create a new migration. If you app is in pre-production stage, and you have a small development team with good communication, then I recommend you to go ahead and modify the migration and then do
rake db:drop
rake db:create
rake db:migrate
then you can commit the modified migration file and let the rest of you team know that that you have changed a migration file.

Resources