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?
Related
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
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
I would like to run the following migration to my Rails(4.x) app but would like to get some feedback from the Rails community first.
class AddUniqueIndexToSchemaMigrations < ActiveRecord::Migration
def change
add_column :schema_migrations, :id, :primary_key
add_index :schema_migrations, ["version"], :name => "unique_versions", :unique => true
end
end
The database in use is MySQL (5.x). Adding this index allows me execute SQL such as:
INSERT INTO schema_migrations
(version)
VALUES ( '2014xxxxxx' )
ON DUPLICATE KEY
UPDATE foo=bar; // or some other bit of cleverness
Is there any reason why this is going off the rails? I don't want to create a situation where I'm fighting against Rails internals.
Thanks in advance!
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
I have looked at Rails Guides and the Rails API and I can't understand the usage of reversible and revert.
So for example, see the example linked here http://guides.rubyonrails.org/migrations.html#using-reversible and included below:\
It says
Complex migrations may require processing that Active Record doesn't know how to reverse. You can use reversible to specify what to do when running a migration what else to do when reverting it. For example,
class ExampleMigration < ActiveRecord::Migration
def change
create_table :products do |t|
t.references :category
end
reversible do |dir|
dir.up do
#add a foreign key
execute <<-SQL
ALTER TABLE products
ADD CONSTRAINT fk_products_categories
FOREIGN KEY (category_id)
REFERENCES categories(id)
SQL
end
dir.down do
execute <<-SQL
ALTER TABLE products
DROP FOREIGN KEY fk_products_categories
SQL
end
end
add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end
I get that the code in the down section is what will be run on rollback, but why include the code in the up block? I have also seen another example which had a reversible section with only an up block. What would the purpose of such code be?
Finally, I do not understand revert. Below is the example included in the Rails Guides, but it makes little sense to me.
`The revert method also accepts a block of instructions to reverse. This could be useful to revert selected parts of previous migrations. For example, let's imagine that ExampleMigration is committed and it is later decided it would be best to serialize the product list instead. One could write:
class SerializeProductListMigration < ActiveRecord::Migration
def change
add_column :categories, :product_list
reversible do |dir|
dir.up do
# transfer data from Products to Category#product_list
end
dir.down do
# create Products from Category#product_list
end
end
revert do
# copy-pasted code from ExampleMigration
create_table :products do |t|
t.references :category
end
reversible do |dir|
dir.up do
#add a foreign key
execute <<-SQL
ALTER TABLE products
ADD CONSTRAINT fk_products_categories
FOREIGN KEY (category_id)
REFERENCES categories(id)
SQL
end
dir.down do
execute <<-SQL
ALTER TABLE products
DROP FOREIGN KEY fk_products_categories
SQL
end
end
# The rest of the migration was ok
end
end
end`
I'm not an expert in this by any means, but my understanding from reading the guides is as follows:
The reversible call in the first example is expressing the second of four components of the change migration. (Note: The indentation you have is misleading in this regard and should probably be updated to match the guide.) It is related to but distinct from the other components, so it makes sense that it would have both an up and down section. I can't explain why you would have reversible with only one direction and not the other, as you indicated you'd seen.
The revert call is telling the system to revert a previous migration either by name or by providing a block describing the (forward) migration. The example you showed is the latter case and I think is best understood by careful reading of the paragraph that follows it in the guide, to wit:
The same migration could also have been written without using revert
but this would have involved a few more steps: reversing the order of
create_table and reversible, replacing create_table by drop_table, and
finally replacing up by down and vice-versa. This is all taken care of
by revert.