Missing table column, defined in migrate - ruby-on-rails

I tried to create a new Link table and specified the necessary columns under migration.
under db/migrate
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.integer :user_id
t.string :url
t.timestamps
end
end
end
class AddTitleToLink < ActiveRecord::Migration
def change
# add_column :links, :user_id, :integer
add_column :links, :title, :string
end
end
When I ran rails console, Link returned
Link(id: integer, created_at: datetime, updated_at: datetime, title: string)
It seems like user_id (the foreign key) and url are missing. Title, which was added later, is in the table.
Did I do anything wrong?

Did you perhaps run the CreateLinks migration before editing it to add the two fields? If so, you can change that file all day long and rake db:migrate will never re-run it. That would explain there being an empty table links, and the field you then added to it in the next migration.
You can step the database back by running rake db:rollback. Try doing that twice, then migrate again.

Can't see any reason for this not to work. Is it possible that you first ran:
rails g model Link
(which generated a migration AND RAN it)
and then you manually added the :url and :user_id?
Try running twice:
rake db:rollback
Then run again
rake db:migrate
which will catch up your manual modifications

Related

Rails error: Index name '...' on table '...' already exists while running rails db:migrate

So I'm working with a colleague who added some additional migration files and per normal procedure once I pulled their version I ran rails db:migrate. I end up getting the following errors:
Index name 'index_authorizations_on_user_id' on table 'authorizations' already exists
ArgumentError: Index name 'index_authorizations_on_user_id' on table 'authorizations' already exists
So I went and checked the schema and the table is already present. So why is it failing? Typically in the past it only generates new table entries/updates when doing a migration so why isn't it just ignoring it?
I've tried doing a rollback and get:
This migration uses remove_columns, which is not automatically reversible.
I've tried doing bin/rails db:migrate RAILS_ENV=development and I get the same errors.
I've done a db:reset, db:drop, and it all comes back to an issue with pending migrations that I cannot get to run. What am I doing wrong?
They added the following migration: 20171024074328_create_authorizations.rb
class CreateAuthorizations < ActiveRecord::Migration[5.1]
def change
create_table :authorizations do |t|
t.string :provider
t.string :uid
t.references :user, foreign_key: true
t.timestamps
add_index :authorizations, :user_id
add_index :authorizations, [:provider, :uid], unique: true
end
end
end
This:
t.references :user, foreign_key: true
adds an index on authorizations.user_id for you. If you check the references documentation it will point you at add_reference and that says:
:index
Add an appropriate index. Defaults to true. [...]
So index: true is the default when you call t.references :user and that creates the same index that add_index :authorizations, :user_id creates.
So the only thing that I've found that "worked" was to actually delete the migration files then run rails db:migrate. Didn't catch on anything, no errors.
Not a fan of the fact that this worked.
Check if it's a table or a changed table, most times you need to drop the table or delete the column then run the migration again and it'll be good to go

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>

Add Id column in a migration

I have a Rails app, where one of the models does not have the id column. Doing some research I found the migration that created it:
create_table(:the_model, :id => false) do |t|
# columns
end
Now, on a new migration, I want to add the id column in a Rails standard way (not using database specific sql). How can I do that?
I already tried this without success:
change_table(:the_model, :id => true) do |t|
end
You can either manually add the id column:
add_column :table_name, :id, :primary_key
or clear (or backup) your data, rollback to this migration, get rid of the option :id => false, and re-migrate.
You don't need to mention :integer
rails g migration add_id_to_model id:primary_key worked for me.
You already got your answer, but here is a one liner that does all in this case
rails generate migration AddIdToModel id:integer
Look at the syntax of migration file name AddColumnNameToTableName followed the column description.
It will generate something like below
class AddIdToModel < ActiveRecord::Migration
def change
add_column :models, :id, :integer
end
end
Now you can change this line if you feel for anything else. and just run rake db:migrate.

Rake aborted... table 'users' already exists

I have created a database with devise and the nifty generator. I'm trying to make a new database with the nifty generator (rails g nifty:scaffold Asset user_id:integer), but when I try to migrate the database (rake db:migrate), I get the following error:
charlotte-dator:showwwdown holgersindbaek$ rake db:migrate
== DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
rake aborted!
An error has occurred, all later migrations canceled:
Mysql2::Error: Table 'users' already exists: CREATE TABLE `users` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `email` varchar(255) DEFAULT '' NOT NULL, `encrypted_password` varchar(128) DEFAULT '' NOT NULL, `reset_password_token` varchar(255), `reset_password_sent_at` datetime, `remember_created_at` datetime, `sign_in_count` int(11) DEFAULT 0, `current_sign_in_at` datetime, `last_sign_in_at` datetime, `current_sign_in_ip` varchar(255), `last_sign_in_ip` varchar(255), `name` varchar(255), `created_at` datetime, `updated_at` datetime) ENGINE=InnoDB
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
I'm following a tutorial and have quite a hard time understanding why this happens. Can anyone explain what is going on?
In your create_users migration (APP_ROOT/db/migrate/..), add drop_table :users right before create_table :users and run rake db:migrate. It will remove the users table before recreating it. You can remove that line of code after running this migration so it doesn't give you errors later on. Just a small fix if you dont have UI access to a database (on heroku, for example).
You need to drop that table from the sql lite console (You will lost all the data contained in it)
Access the sql lite console, type in terminal
mysql <DB NAME HERE>
Drop table (dont forget the last ; (semicolon))
drop table table_name;
run db:migrate again
bin/rake db:migrate
Hope it helps, it worked for me
If you wanna play safe and don't want to lose any data then you can check if the table exists in your database.
class DeviseCreateUsers < ActiveRecord::Migration
def up
if table_exists?(:users)
# update or modify columns of users table here accordingly.
else
# create table and dump the schema here
end
end
def down
# same approach goes here but in the reverse logic
end
end
The migration is trying to create a table that already exists in your database.
Try to remove the user table from your database. Something went wrong with you migration process. You should also compare your schema.rb version with your db/migrate/*.rb files.
Clarification:
It seems that many SO users don't agree with my reply, either because they consider it inaccurate or not recommended.
Removing a table is always destructive, and I think that everyone understands that.
I should have mentioned add_column, since the table was being created in another migration file.
If you know the database was created properly, you can just comment out the creation part of the migration code. For example:
Class ActsAsVotableMigration < ActiveRecord::Migration
def self.up
# create_table :votes do |t|
#
# t.references :votable, :polymorphic => true
# t.references :voter, :polymorphic => true
#
# t.boolean :vote_flag
#
# t.timestamps
# end
#
# add_index :votes, [:votable_id, :votable_type]
# add_index :votes, [:voter_id, :voter_type]
end
def self.down
drop_table :votes
end
end
If the table was created, but later commands weren't completed for some reason, you can just leave the later options for example:
Class ActsAsVotableMigration < ActiveRecord::Migration
def self.up
# create_table :votes do |t|
#
# t.references :votable, :polymorphic => true
# t.references :voter, :polymorphic => true
#
# t.boolean :vote_flag
#
# t.timestamps
# end
add_index :votes, [:votable_id, :votable_type]
add_index :votes, [:voter_id, :voter_type]
end
def self.down
drop_table :votes
end
end
If you don't have any significant data in your database to preserve however you can just have it drop the table and all the data and create it fresh. For example (notice the "drop_table :votes", in the self.up):
class ActsAsVotableMigration < ActiveRecord::Migration
def self.up
drop_table :votes
create_table :votes do |t|
t.references :votable, :polymorphic => true
t.references :voter, :polymorphic => true
t.boolean :vote_flag
t.timestamps
end
add_index :votes, [:votable_id, :votable_type]
add_index :votes, [:voter_id, :voter_type]
end
def self.down
drop_table :votes
end
end
Don't delete tables. Data > migrations!
The version of the database already reflects the changes the error-causing migration is trying to add. In other words, if the migration could be skipped, then everything would be fine. Check the db_schema_migrations table and try inserting the version of the erroneous migration (e.x, 20151004034808). In my case this caused subsequent migrations to execute perfectly and everything seems fine.
Still not sure what caused this problem.
If your app is new and you don't care about the data in your database, simply:
rake db:reset
I think this is an issue unique or more common to mysql in rails, possible having to do with the mysql2 gem itself.
I know this because I just switched from sqlite to mysql and just started having this problem systematically.
In my case, I simply commented out the code that had already run and ran the migration again (which I'm not adding more detail to because it looks like the guy above me did that).
I had a similar problem when trying to add Devise authentication to an existing Users table.
My solution: I found that I had two migrate files, both trying to create the Users table. So rather than deleting the table (probably not the best habit to form), I commented out the first (original) migrate file that created the Users table and then left the Devise migrate file as-is. Re-ran the migration and it worked fine.
As it turns out, the Devise file wasn't causing the problem; I can see that it is "changing" the table, not "creating it", which means that even without the devise installation, a db:migrate probably would have caused the same issue (though I haven't tested this).
If you want to keep your data, rename the table, but do it in the migration to save time, then remove it once the migration has ran.
Place at the top part of the up section of the migration file.
rename_table :users, :users2

Resources