Multiple foreign keys referencing the same table in RoR

Viewed 28038

I want a Customer to reference two Address models, one for the billing address and one for the shipping address. As I understand it, the foreign key is determined by its name, as _id. Obviously I can't name two rows address_id (to reference the Address table). How would I do this?

create_table :customers do |t|
  t.integer :address_id
  t.integer :address_id_1 # how do i make this reference addresses table?
  # other attributes not shown
end
5 Answers

This sounds like a has_many relationship to me - put the customer_id in the Address table instead.

Customer
  has_many :addresses

Address
  belongs_to :customer

You can also provide a foreign key and class in the assoc declaration

Customer
   has_one :address
   has_one :other_address, foreign_key => "address_id_2", class_name => "Address"

I figured out how to do it thanks to Toby:

class Address < ActiveRecord::Base
  has_many :customers
end
class Customer < ActiveRecord::Base
  belongs_to :billing_address, :class_name => 'Address', :foreign_key => 'billing_address_id'
  belongs_to :shipping_address, :class_name => 'Address', :foreign_key => 'shipping_address_id'
end

The customers table includes shipping_address_id and billing_address_id columns.

This is essentially a has_two relationship. I found this thread helpful as well.

In Rails 5.1 or greater you can do it like this:

Migration

create_table(:customers) do |t|
    t.references :address, foreign_key: true
    t.references :address1, foreign_key: { to_table: 'addresses' }
end

This will create the fields address_id, and address1_id and make the database level references to the addresses table

Models

class Customer < ActiveRecord::Base
  belongs_to :address
  belongs_to :address1, class_name: "Address"
end

class Address < ActiveRecord::Base
  has_many :customers,
  has_many :other_customers, class_name: "Customer", foreign_key: "address1_id"
end

FactoryBot

If you uses FactoryBot then your factory might look something like this:

FactoryBot.define do
  factory :customer do
    address
    association :address1, factory: :address
  end
end
Related