In my rails app, I want to add a unique constraint to my favourites model. (I'm remaking a basic twitter app, with users and tweets, and generated a third model for favourite). However when I try and add a unique constraint to my favourites model so that one user can favourite a tweet only once, then run the command
rake db:migrate, I get the following error:
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::ConstraintException: UNIQUE constraint failed: favourites.user_id, favourites.tweet_id: CREATE UNIQUE INDEX "index_favourites_on_user_id_and_tweet_id" ON "favourites" ("user_id", "tweet_id")/Users/Tabish/.rvm/gems/ruby-2.2.0/gems/sqlite3-1.3.10/lib/sqlite3/statement.rb:108:in `step'
Here is how my migration file that I have created looks:
class AddUniqueConstraintToTweets < ActiveRecord::Migration
def change
add_index :favourites, [:user_id, :tweet_id], :unique => true
end
end
Also here is my favourites table migration file:
class CreateFavourites < ActiveRecord::Migration
def change
create_table :favourites do |t|
t.references :user, index: true
t.references :tweet, index: true
t.timestamps null: false
end
add_foreign_key :favourites, :users
add_foreign_key :favourites, :tweets
end
end
I am using Rails 4.2.0 and SQLite3
As #mu mentioned, this means that you can't apply this index, because in your current database state you have duplicated user_id, tweet_id pairs. So you should remove them before running a migration.
To find them, open console and fire this command, which will show you those duplicates:
Favourite.select('user_id, tweet_id').group(:user_id, :tweet_id).having('count(*) > 1')
Related
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
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.
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've tried a bunch of variations of this migration file:
class CombineTags < ActiveRecord::Migration
def change
create_join_table :habits, :valuations, :quantifieds, :goals do |t|
t.timestamps null: false
end
t.index :habits, [:habit_id, :tag_list], :valuations, [:valuation_id, :tag_list], :quantifieds, [:quantified_id, :tag_list] :goals, [:goal_id, :tag_list]
end
end
but I keep getting this error upon running rake db:migrate:
Anthony-Gallis-MacBook-Pro:pecoce galli01anthony$ rake db:migrate
== 20150506172844 CombineTags: migrating ======================================
-- create_join_table(:habits, :valuations, :quantifieds, :goals)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
wrong number of arguments (4 for 2..3)/Users/galli01anthony/.rvm/gems/ruby-2.1.3/gems/activerecord-4.2.0.rc3/lib/active_record/connection_adapters/abstract/schema_statements.rb:248:in `create_join_table'
This is just one step in trying to achieve my ultimate goal: How to use multiple models for tag_cloud?
The create_join_table accept only 3 args (last of them is optionals, look at link). So, you can't create join table for 3 tables use this method.
In you case you should create join table use create_table and specify correspond reference fields.