I have two set up two database tables called 'points' and 'activities'. I want to give the table 'points' a foreign key 'activity_id' by setting up the associations as follows:
class Activity < ActiveRecord::Base
belongs_to :user
has_many :points, dependent: :destroy
...
end
and
class Point < ActiveRecord::Base
belongs_to :activity
end
In addition, I have the following migrations file for creating the points table:
class CreatePoints < ActiveRecord::Migration
def change
create_table :points do |t|
t.integer :activity_id
t.timestamps null: false
t.boolean :activities_completed, array: true, default: []
t.integer :point_value
t.float :time_left
end
end
end
However, when I run
rake db:reset
rake db:migrate
rake db:seed
and then check the the table points by
rails c
Point.column_names
then the foreign key is missing:
irb(main):001:0> Point.column_names
=> ["id", "created_at", "updated_at", "activities_completed", "point_value", "time_left"]
What am I doing wrong? What can I do to make the foreign key activity_id a column of the points table?
I am new to Ruby and Rails. My Rails version is 4.24. Any help is appreciated.
Your create table migration should have a "t.belongs_to :activity, index: true" instead of creating the field activity_id with type integer.
You should have done something like this to add activity_id to your points table.
t.references :activity, index: true, foreign_key: true
#this would have created activity_id column in points
Since now, you have already created your migrations and ran rake db:migrate, learn to remove a column from a table. You need to write migrations to remove activity_id from your points table and add it again.
rails generate migration RemoveActivityIdFromPoints activity_id:integer
rails g migration AddActivityRefToPoints activity:references
These two should create proper migrations for you. Check your migrations folder for confirmation that everything went well, and run rake db:migrate and test again.
Follow this link to learn more about it. http://guides.rubyonrails.org/active_record_migrations.html
I discovered that there was a more fundamental problem. The migration script was not being executed during rake db:migrate. Therefore the changes I had made to the migration were ineffective. I therefore had to use
rake db:migrate:redo VERSION=20160605234351
When I ran this command, then the foreign key appeared.
Related
I have a Rails 6 app (6.0.0rc1). It has book and author models that have has_many :through associations. I created a join table with
rails g migration CreateJoinTableAuthorsBook author:references books:references
As you can see, I named the table incorrectly and I referenced the book incorrectly. I deleted the migration and created a new migration
rails g migration CreateJoinTableAuthorsBooks author:references book:references
Now when I run the migration, I get
ArgumentError: you can't define an already defined column 'author_id'.
I've searched my entire Rails app, but I can't find 'author_id' anywhere. I ran the previous migration (the one with the incorrect values). How can I delete the previous 'author_id' so I can successfully run the migration?
UPDATE The problem likely lies in the new migration. In Rails 5.2 (I don't have Rails 6 handy) rails g migration CreateJoinTableAuthorsBooks author:references book:references produces a migration like so:
create_join_table :authors, :books do |t|
t.references :author, foreign_key: true
t.references :book, foreign_key: true
end
create_join_table :authors, :books already creates a table with references (although they're not declared foreign keys). t.references :author and t.references :book are redundant. In Rails 5.2 this redundancy is overlooked, but perhaps Rails 6 does not.
For this reason I'd recommend tweaking your migration so everything is properly declared and indexed.
create_join_table :authors, :books, column_options: { null: false, foreign_key: true } do |t|
t.index [:author_id, :book_id]
t.index [:book_id, :author_id]
end
The normal procedure for fixing a goofed migration is to first rollback the migration with rails db:rollback, then delete the bad migration file. Rolling back requires the migration you're rolling back still exists (and is reversible).
Otherwise, start with a fresh development database using the version in db/schema.rb with rails db:reset. Note this will blow away your dev and test databases; that shouldn't be an issue. Be sure your db/schema.rb doesn't contain changes from your goofed migration, usually you can assure this by checking it out from version control.
Finally if everything is really messed up including db/schema.rb, rails db:migrate:reset will re-run all your migrations, rebuild db/schema.rb fresh, and provide you with fresh development and test databases.
create_join_table :authors, :books
will fix it for you as rails 6 doesn't need those declarations.
I had this same issue when working on a Rails 6 application.
== 20200711132707 CreateProducts: migrating ===================================
-- create_table(:products)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
you can't define an already defined column 'voltage'.
Here’s how I fixed it:
The issue was that I defined a model attribute twice, which in this case was voltage:decimal. So when I run rails db:migrate it throws the error.
I fixed by first deleting the migration file for products.
And then recreating the migration for products.
This time when I ran rails db:migrate everything worked well.
That's all.
I hope this helps
I had the same issue,
you do NOT need anymore the references:
# remove these:
t.references :author, foreign_key: true
t.references :book, foreign_key: true
Note: you can still use the options used in t.references with create_join_table, using the column_options arg.
For example:
create_join_table :authors, :books, column_options: { type: :uuid, null: false, index: true, foreign_key: true } do |t|
...
end
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
On migration I get the following error message:
PG::UndefinedTable: ERROR: relation "actioncodes" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_4ecaa2493e"
FOREIGN KEY ("actioncode_id")
REFERENCES "actioncodes" ("id")
I have the following migration file for Organizations:
class CreateOrganizations < ActiveRecord::Migration
def change
create_table :organizations do |t|
t.string :name, null: false, limit: 40
t.references :actioncode, index: true, foreign_key: true
t.boolean :activated
t.datetime :activated_at
t.timestamps null: false
end
end
end
And for Actioncodes I have the migration file:
class CreateActioncodes < ActiveRecord::Migration
def change
create_table :actioncodes do |t|
t.string :code, null: false, limit: 20
t.string :description, limit: 255
t.timestamps null: false
end
end
end
class AddIndexToActioncodesCode < ActiveRecord::Migration
def change
add_index :actioncodes, :code, unique: true
end
end
The organization model file includes: belongs_to :actioncode.
While the actioncodes model file includes: has_many :organizations.
Any idea what could be causing the error message?
If I remove index: true, foreign_key: true from the migration file, it migrates without errors. And when I replace that line with the incorrect line t.references :actioncode_id, index: true, foreign_key: true, it gives the error below, where the last line ("ids") suggests Rails somehow seems to have problem with the name of the table?
PG::UndefinedTable: ERROR: relation "actioncode_ids" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_604f95d1a1"
FOREIGN KEY ("actioncode_id_id")
REFERENCES "actioncode_ids" ("id")
So the issue is happening because CreateOrganizations migration is being run before CreateActioncodes is executed.
CreateActioncodes is to be run first thereby ensuring that the action codes table exists.
The order in which migrations are run is based on the time stamp of the migration - as indicated in the name of the file. 20141014183645_create_users.rb will run before 20141014205756_add_index_to_users_email.rb as the timestamp of the second one - 20141014205756 is after that of the first one - 20141014183645.
Make sure the time-stamps of the CreateOrganizations migration is after that of CreateActioncodes migration.
Either you could manually change the timestamp in the file names. Or delete these migration files, and create them in the correct order.
The foreign_key: true in this line:
t.references :actioncode, index: true, foreign_key: true
tells Rails to create a foreign key inside the database. A foreign key:
constraint specifies that the values in a column (or a group of columns) must match the values appearing in some row of another table. We say this maintains the referential integrity between two related tables.
So it is some logic inside the database (where it belongs) that ensures you can't put invalid values in your actioncode column and that you can't remove entries from the actioncodes table that are being used elsewhere.
In order to create the constraint, the referenced table (actioncodes) needs to exist before you refer to it. Looks like your migrations are trying to create organizations before actioncodes so all you need to do is rename the CreateOrganizations migration file so that its timestamp prefix comes after the one for CreateActioncodes. The prefix is just a timestamp in the format YYYYMMDDhhmmss so change the CreateOrganizations timestamp to the CreateActioncodes timestamp with one more second.
I was also getting this error. If you are using a test database to run rspec make sure you run rake db:test:prepare in the terminal before running rspec.
I had this same challenge when working on a Rails 6 application in Ubuntu 20.04.
I am working on a College Portal where I have model called School and another called Program. The model Program belongs to the model School, so it is required that I add a school references column to the programs table.
I used this command this create the migration file:
rails generate model School name:string logo:json motto:text address:text
rails generate model Program name:string logo:json motto:text school_id:references
However, when I run the command: rails db:migrate
I was getting the error:
== 20201208043945 CreateSchools: migrating ====================================
-- create_table(:schools)
-> 0.0140s
== 20201208043945 CreateSchools: migrated (0.0141s) ===========================
== 20201208043958 CreatePrograms: migrating ===================================
-- create_table(:programs)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "school_ids" does not exist
Here's how I solved it:
The issue was from the command:
rails generate model Program name:string logo:json motto:text school_id:references
It is supposed to be school:references and not school_id:references, so during the migration Rails is unable to find the table school_ids.
So I modified the command to:
rails generate model Program name:string logo:json motto:text school:references
And it worked fine.
That's all.
I hope this helps
On migration I get the following error message:
PG::UndefinedTable: ERROR: relation "actioncodes" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_4ecaa2493e"
FOREIGN KEY ("actioncode_id")
REFERENCES "actioncodes" ("id")
I have the following migration file for Organizations:
class CreateOrganizations < ActiveRecord::Migration
def change
create_table :organizations do |t|
t.string :name, null: false, limit: 40
t.references :actioncode, index: true, foreign_key: true
t.boolean :activated
t.datetime :activated_at
t.timestamps null: false
end
end
end
And for Actioncodes I have the migration file:
class CreateActioncodes < ActiveRecord::Migration
def change
create_table :actioncodes do |t|
t.string :code, null: false, limit: 20
t.string :description, limit: 255
t.timestamps null: false
end
end
end
class AddIndexToActioncodesCode < ActiveRecord::Migration
def change
add_index :actioncodes, :code, unique: true
end
end
The organization model file includes: belongs_to :actioncode.
While the actioncodes model file includes: has_many :organizations.
Any idea what could be causing the error message?
If I remove index: true, foreign_key: true from the migration file, it migrates without errors. And when I replace that line with the incorrect line t.references :actioncode_id, index: true, foreign_key: true, it gives the error below, where the last line ("ids") suggests Rails somehow seems to have problem with the name of the table?
PG::UndefinedTable: ERROR: relation "actioncode_ids" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_604f95d1a1"
FOREIGN KEY ("actioncode_id_id")
REFERENCES "actioncode_ids" ("id")
So the issue is happening because CreateOrganizations migration is being run before CreateActioncodes is executed.
CreateActioncodes is to be run first thereby ensuring that the action codes table exists.
The order in which migrations are run is based on the time stamp of the migration - as indicated in the name of the file. 20141014183645_create_users.rb will run before 20141014205756_add_index_to_users_email.rb as the timestamp of the second one - 20141014205756 is after that of the first one - 20141014183645.
Make sure the time-stamps of the CreateOrganizations migration is after that of CreateActioncodes migration.
Either you could manually change the timestamp in the file names. Or delete these migration files, and create them in the correct order.
The foreign_key: true in this line:
t.references :actioncode, index: true, foreign_key: true
tells Rails to create a foreign key inside the database. A foreign key:
constraint specifies that the values in a column (or a group of columns) must match the values appearing in some row of another table. We say this maintains the referential integrity between two related tables.
So it is some logic inside the database (where it belongs) that ensures you can't put invalid values in your actioncode column and that you can't remove entries from the actioncodes table that are being used elsewhere.
In order to create the constraint, the referenced table (actioncodes) needs to exist before you refer to it. Looks like your migrations are trying to create organizations before actioncodes so all you need to do is rename the CreateOrganizations migration file so that its timestamp prefix comes after the one for CreateActioncodes. The prefix is just a timestamp in the format YYYYMMDDhhmmss so change the CreateOrganizations timestamp to the CreateActioncodes timestamp with one more second.
I was also getting this error. If you are using a test database to run rspec make sure you run rake db:test:prepare in the terminal before running rspec.
I had this same challenge when working on a Rails 6 application in Ubuntu 20.04.
I am working on a College Portal where I have model called School and another called Program. The model Program belongs to the model School, so it is required that I add a school references column to the programs table.
I used this command this create the migration file:
rails generate model School name:string logo:json motto:text address:text
rails generate model Program name:string logo:json motto:text school_id:references
However, when I run the command: rails db:migrate
I was getting the error:
== 20201208043945 CreateSchools: migrating ====================================
-- create_table(:schools)
-> 0.0140s
== 20201208043945 CreateSchools: migrated (0.0141s) ===========================
== 20201208043958 CreatePrograms: migrating ===================================
-- create_table(:programs)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "school_ids" does not exist
Here's how I solved it:
The issue was from the command:
rails generate model Program name:string logo:json motto:text school_id:references
It is supposed to be school:references and not school_id:references, so during the migration Rails is unable to find the table school_ids.
So I modified the command to:
rails generate model Program name:string logo:json motto:text school:references
And it worked fine.
That's all.
I hope this helps
I'm totally stuck here! I want to add a unique index so that no two records in an association table can have the same combination of user_id and course_id.
I have created the following migration file in rails:
class CreateSignups < ActiveRecord::Migration
def change
create_table :signups do |t|
t.integer :course_id
t.integer :user_id
t.timestamps null: false
end
add_index :signups, :course_id
add_index :signups, :user_id
add_index :signups, [:course_id, :user_id], unique: true
end
end
...but for some reason, the unique 'course_id & user_id' is not being represented in the schema.rb and using the rails console the system lets me manually create a multiple records where the course_id and the user_id are exactly the same.
The signups table is managed by the Signup model and has an integer primary key called 'id'. The course and user Model & database table follow standard rails naming convention.
Can anyone see why it's the unique criteria is not being understood in this migration?
Thanks in advance!
Did you already run your migration once (to create table) and then add the index? You can check it by doing following:
bundle exec rails dbconsole
select * from schema_migrations;
If your migration version is already recorded in the schema_migrations table, and doing rake db:migrate won't run it again.
To add indexes, you have 2 options:
Rollback the migration for CreateSignups. This will drop the current table and then doing rake db:migrate will re-create the table with indexes.
If you don't want to loose the data in previous step, then you'll have to explicitly create indexes in MySQL from rails dbconsole.