Remove a foreign key column using a Rails migration - ruby-on-rails

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

Related

Remove _id suffix from foreign key migration

I am trying to add a foreign key to via migration. It works as expected, but it automatically adds _id to the end (the column name I want to reference doesn't include _id). How can I make it reference the column name as I give it?
Here is the migration
class ChangeRefOnMemberPresentations < ActiveRecord::Migration[5.2]
def change
add_reference :member_presentations, 'employee_number', foreign_key: { to_table: :users }
end
end
Which results in both the reference column name and foreign key reference column being called employee_number_id in schema.rb
The following worked by defining everything manually, but seems messy. If there is a better migration answer, I'll be happy to accept.
def change
# column was added in another migration, but including for completness
add_column :member_presentations, :employee_number, :bigint
add_index :member_presentations, :employee_number, name: "index_member_presentations_on_employee_number"
add_foreign_key :member_presentations, :users, column: "employee_number"
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

Rails migration with add_foreign_key: 'column "user_id" referenced in foreign key constraint does not exist'

(Rails is version 5.0.0, Ruby 2.3.0p0)
I want to create an association between my Users table and Cards table. I've added belongs_to :user to the Cards model, and has_many :cards to the Users model, and created a migration with:
class AddUserIdToCard < ActiveRecord::Migration[5.0]
def change
add_foreign_key :cards, :users, column: :user_id
end
end
When I run rake db:migrate, I receive the error:
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column "user_id" referenced in foreign key constraint does not exist
: ALTER TABLE "cards" ADD CONSTRAINT "fk_rails_8ef7749967"
FOREIGN KEY ("user_id")
REFERENCES "users" ("id")
Now I initially worked around this problem simply by adding add_column :cards, :user_id, :integer to the migration, but that doesn't really seem very tidy, and I'm worried about problems coming up later. Is there a better way to accomplish this?
You're setting a foreign key for cards table with the column user_id. But you haven't created a reference yet. Create a reference and then add foreign key to maintain referential integrity. Rollback and modify your migration with
1 class AddUserIdToCard < ActiveRecord::Migration[5.0]
2 def change
3 add_reference :cards, :users, index:true
4 add_foreign_key :cards, :users
5 end
6 end
Line 3 will create, in the cards table, a reference to id in the users table (by creating a user_id column in cards).
Line 4 will add a foreign key constraint to user_id at the database level.
For more, read Add a reference column migration in Rails 4
The answer provided is not accurate for Rails 5. Scroll to the add_reference bit of the docs for more, but in the case of the above question, you would use:
class AddUserIdToCard < ActiveRecord::Migration[5.0]
def change
add_reference :cards, :users, foreign_key: true
end
end
In rails 6, I believe this is now
def change
add_column :cards, :user_id, :integer, index: true
add_foreign_key :cards, :users
end
class AddUserIdToCard < ActiveRecord::Migration[5.2]
def change
add_foreign_key :cards, :users, column: :user_id, primary_key: :"id", on_delete: :cascade
end
end
Try this migration. I was facing the same problem then I fixed it.

Change Primary Key Issue Rails 4.0

I followed this guide on how to change the Primary Key:
http://www.lshift.net/blog/2013/09/30/changing-the-primary-key-type-in-ruby-on-rails-models/comment-page-1
Here is my code:
class Pk2 < ActiveRecord::Migration
def up
remove_column :contracts, :id # remove existing primary key
rename_column :contracts, :contractId, :id # rename existing UDID column
execute "ALTER TABLE contracts ADD PRIMARY KEY (id);"
end
def down
# Remove the UDID primary key. Note this would differ based on your database
execute "ALTER TABLE contracts DROP CONSTRAINT table_pkey;"
rename_column :contracts, :id, :contractId
add_column :contracts, :id, :primary_key
end
end
The error I keep getting is "Syntax around ALTER TABLE table ADD PRIMARY KEY"
Please help. Thank you.
The answer seemed to be that the OP separated the migration into 3 files:
1. Remove `:id` column
2. Rename `:contractId` column to `:id`
3. run `execute "ALTER TABLE contracts ADD PRIMARY KEY (id);"`
This allowed the OP to successfully run the migration
Some other resources:
Using Rails, how can I set my primary key to not be an integer-typed column?
Problems setting a custom primary key in a Rails 4 migration

Difference between foreign key constraint and references in Rails

Is there any difference between using t.references and executing SQL command to create foreign key relationship between products and category table as shown below? In other words, are the two different ways of doing the same thing or am I missing anything here?
class ExampleMigration < ActiveRecord::Migration
def up
create_table :products do |t|
t.references :category
end
#add a foreign key
execute <<-SQL
ALTER TABLE products
ADD CONSTRAINT fk_products_categories
FOREIGN KEY (category_id)
REFERENCES categories(id)
SQL
add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end
def down
rename_column :users, :email_address, :email
remove_column :users, :home_page_url
execute <<-SQL
ALTER TABLE products
DROP FOREIGN KEY fk_products_categories
SQL
drop_table :products
end
end
They're not the same thing. Rails by default doesn't enforce foreign keys in the database. Instead, references when creating from the command line also creates a regular index, like this:
add_index :products, :category_id
Update:
Rails 5 actually does exactly the same thing now. So, to answer the original question: Nowadays, both are the same.
I found some thing intresting in this page.
http://railsforum.com/viewtopic.php?id=17318
From a comment :
Rails doesn't use foreign keys to perform his backend tasks. This
because some db like sqlite doesn't allow foreign keys on its tables.
So Rails doesn't provide an helper to build a foreign key
Also there is a gem foreigner for adding foreign keys to database table.
What creates the FOREIGN KEY constraint in Ruby on Rails 3?

Resources