0

I am using rails 4.2, I just want to know if there would be any difference if I use the :foreign_key keyword in my migrations rather than just adding a user_id column to add relationship to my models ?

  • Possible duplicate of [Does Rails need database-level constraints?](http://stackoverflow.com/questions/2589509/does-rails-need-database-level-constraints) – Michael Berkowski May 14 '16 at 12:52

1 Answers1

4

YES

The key difference is not on the application layer but on the database layer - foreign keys are used to make the database enforce referential integrity.

Lets look at an example:

class User < ActiveRecord::Base
  has_many :things
end

class Thing < ActiveRecord::Base
  belongs_to :user
end

If we declare things.user_id without a foreign key:

class CreateThings < ActiveRecord::Migration
  def change
    create_table :things do |t|
      t.integer :user_id

      t.timestamps null: false
    end
  end
end

ActiveRecord will happily allow us to orphan rows on the things table:

user = User.create(name: 'Max')
thing = user.things.create
user.destroy
thing.user.name # Boom! - 'undefined method :name for NilClass'

While if we had a foreign key the database would not allow us to destroy user since it leaves an orphaned record.

class CreateThings < ActiveRecord::Migration
  def change
    create_table :things do |t|
      t.belongs_to :user, index: true, foreign_key: true

      t.timestamps null: false
    end
  end
end

user = User.create(name: 'Max')
thing = user.things.create
user.destroy # DB says hell no

While you can simply regulate this with callbacks having the DB enforce referential integrity is usually a good idea.

# using a callback to remove associated records first
class User < ActiveRecord::Base
  has_many :things, dependent: :destroy
end
max
  • 96,212
  • 14
  • 104
  • 165
  • Make sure you index the foreign key column -- you probably would anyway, but with a foreign key declared in the database it would be wise to make sure that you do. There is a gem which helps with that ... don't remember the name ... – David Aldridge May 15 '16 at 22:59
  • I think you may be thinking of [foreigner](https://github.com/matthuhiggins/foreigner) however you don't need a gem to add foreign keys or indexes in a later migration - and it is done anyways if you use the `belongs_to` macro when declaring the column http://guides.rubyonrails.org/active_record_migrations.html#foreign-keys – max May 16 '16 at 10:39