Foreign Key in Rails - Errors - ruby-on-rails

I'm trying to add a new foreign key column to my Customers table. This is my migration:
class AddCompanyForeignKeyToCustomers < ActiveRecord::Migration[5.1]
def change
add_reference :customers, :company, foreign_key: true
add_foreign_key :customers, :companies
end
end
These are the errors I'm getting:
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::DuplicateObject: ERROR: constraint "fk_rails_ef51a916ef" for relation "customers" already exists
: ALTER TABLE "customers" ADD CONSTRAINT "fk_rails_ef51a916ef"
FOREIGN KEY ("company_id")
REFERENCES "companies" ("id")
ActiveRecord::StatementInvalid: PG::DuplicateObject: ERROR: constraint "fk_rails_ef51a916ef" for relation "customers" already exists
: ALTER TABLE "customers" ADD CONSTRAINT "fk_rails_ef51a916ef"
FOREIGN KEY ("company_id")
REFERENCES "companies" ("id")
PG::DuplicateObject: ERROR: constraint "fk_rails_ef51a916ef" for relation "customers" already exists
What does any of that mean? I don't know what fk_rails_$NUMBER is.

It means that you are trying to create a foreign key constraint that duplicates one you already have.
This line creates a foreign key constraint on customers referencing companies, as well as creates the company_id column
add_reference :customers, :company, foreign_key: true
This line is trying to do the foreign key constraint again
add_foreign_key :customers, :companies
Just remove one or the other, depending on whether or not you also need to add the company_id column

You're trying to add foreign keys twice by calling add_reference and add_foreign_key. The docs will tell you more, but basically add_foreign_key adds a key and add_reference can add a foreign key (which you are doing with foreign_key: true in your code above), so you should just use one or the other.
If I were you I would just use add_foreign_key, it seems more suited to what you're trying to do:
class AddCompanyForeignKeyToCustomers < ActiveRecord::Migration[5.1]
def change
add_foreign_key :customers, :companies
end
end

Related

Remove a foreign key column using a Rails migration

I am simply trying to remove a foreign key column from a table. I have this in migration:
def change
remove_column :addresses, :contact_id
end
However, I get the following error:
Mysql2::Error: Cannot drop index 'index_addresses_on_contact_id':
needed in a foreign key constraint: ALTER TABLE addresses DROP
contact_id
So how do I remove this foreign key constraint in the Rails migration too?
Try...
def change
remove_reference :addresses, :contact, index: true, foreign_key: true
end

ActiveRecord complains column (for reference) doesn't exist, so I create it manually and it complains it does exist

Assuming for the following migration:
class AddSectionReferences < ActiveRecord::Migration
def change
add_reference :sections, :sections, index: true, foreign_key: true, on_delete: :nullify
add_reference :sections, :parent
end
end
It complains:
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column "section_id" referenced in foreign key constraint does not exist
: ALTER TABLE "sections" ADD CONSTRAINT "fk_rails_810c69e885"
so if I add:
add_column :sections, :sections_id, :integer
before the reference it then complains:
ActiveRecord::StatementInvalid: PG::DuplicateColumn: ERROR: column "sections_id" of relation "sections" already exists
: ALTER TABLE "sections" ADD "sections_id" integer
What is going on, why is it looking for a section_id column in the first error when I'm trying to create a plural column (for a has_many)?
when I'm trying to create a plural column (for a has_many)?
You're approaching this from the wrong end. How do you imagine this column to contain multiple/infinite ids? It's not how rails expects things to be.
In a has_many relationship, the foreign key column is on the belongs_to side. And column name should be singular, naturally. For it can only hold one id.
t.references :section

How to add foreign key constraint in rails which is not have id column

I have a model User and there we have primary_key as user_id instead of id, I know I should use id for primary_key but clients wants we should use user_id instead of id.
I have a other table and I have to relate that table with user_id
I am adding migration like this for other table:
t.references :user, index: true, foreign_key: true
But when I run the migration i get an error related to foreign key constraints like:
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column "id" referenced in foreign key constraint does not exist
ALTER TABLE "user_devices" ADD CONSTRAINT "fk_rails_e700a96826"
FOREIGN KEY ("user_id")
REFERENCES "users" ("id")
It seems rails default try to point other table with id column but I have user_id in users table.
So how can I add foreign key constraints like:
ALTER TABLE "user_devices" ADD CONSTRAINT "fk_rails_e700a96826"
FOREIGN KEY ("user_id")
REFERENCES "users" ("user_id")
with rails migrations?
You can create a separate migration like this:
add_column :user_devices,:user_id,:integer
add_foreign_key :user_devices, :users, column: :user_id, primary_key: "user_id"

Can't add foreign key on relation table

I have two models:
class BracketMatch < ActiveRecord::Base
belongs_to :match
belongs_to :bracket
end
and
class Bracket < ActiveRecord::Base
has_many :bracket_matches
# Has a STI column
end
I am trying to add a foreign key to the table bracket_matches.
add_foreign_key :bracket_matches, :brackets
Raises the following error
PG::ForeignKeyViolation: ERROR: insert or update on table "bracket_matches" violates foreign key constraint "fk_rails_39684e0d9b"
DETAIL: Key (bracket_id)=(122) is not present in table "brackets".
: ALTER TABLE "bracket_matches" ADD CONSTRAINT "fk_rails_39684e0d9b"
FOREIGN KEY ("bracket_id")
REFERENCES "brackets" ("id")
What am I doing wrong and why is it checking bracket_id on brackets instead of bracket_matches?
rails g migration AddFieldToBracketMatches bracket:references
Check your migration file and then rake db:migrate
Edit
In that case why not just rails g migration RemoveColumnFromBrackMatches , remove_column :bracket_matches, :bracket , rake db:migrate, then delete both those migration files and create the migration I suggested above
Add index:true like this
add_foreign_key :bracket_matches, :brackets ,index:true,foreign_key:true

Rails Postgres Schema references rollback issue

In my rails application I have multiple postgresql schemas.
SHOW search_path;
search_path
--------------
"$user",public,vehicle
I have two tables (dealers, inventories) in the vehicle schema. The relationship holds like this:
dealer has_many inventories
inventory belongs_to dealer
I created a migration to add the relationship as:
class AddDealerIdToVehicleInventories < ActiveRecord::Migration
def change
add_reference 'vehicle.inventories', :dealer, index: true, foreign_key: {on_delete: :cascade}
end
end
This migration works perfectly when I run: rake db:migrate, the foreign_key seems added to the table without any issue. But when I run rake db:rollback, I am getting this error message:
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedColumn: ERROR: column "vehicle.dealer_id" referenced in foreign key constraint does not exist
: ALTER TABLE "vehicle"."inventories" ADD CONSTRAINT "fk_rails_95ee16593d"
FOREIGN KEY ("vehicle.dealer_id")
REFERENCES "vehicle"."dealers" ("id")
ON DELETE CASCADE
I am not sure if I am making any mistakes or is the rails migration bug. Thanks for the help.
I solved the issue by making changes in the migration file as:
class AddDealerIdToVehicleInventories < ActiveRecord::Migration
def up
add_reference 'vehicle.inventories', :dealer, index: true, foreign_key: {on_delete: :cascade}
end
def down
execute <<-SQL
ALTER TABLE vehicle.inventories
DROP COLUMN dealer_id
SQL
end
end
Hope, this is useful for others too.

Resources