Tutorial :Rails Model and DB schema with two foreign keys from the same table


I'm developing the Order Model for a Rails application.I'm trying to represent an Order which has BillToAddressId and ShipToAddressId as the foreign keys from the Address table.

The address table is below :

create_table :addresses do |t|        t.string :country        t.string :state        t.string :city        t.string :zipcode        t.string :line1        t.timestamps  

I'm a Rails newbie, so I'm not sure how to represent this in the DB/migrate for Order and Address.

It would be great if someone can guide me to build the Model and migrate script.


You can do it in follwing way

class Order < ActiveRecord::Base    belongs_to :bill_to, :class_name => 'Address', :foreign_key => 'BillToAddressId'    belongs_to :ship_to, :class_name => 'Address', :foreign_key => 'ShipToAddressId'  end  

For Ruby Naming Conevention Column name "ShipToAddressId" must be "ship_to_address_id"


Important: You should not allow users to delete or modify addresses, given the way you are modeling the relationship between Orders and Addresses. If you do, the billing or shipping addresses on Orders that have already taken place can end up modified or deleted, which is a very bad thing. To avoid this, only allow users to add new addresses or mark existing ones as inactive.

With that out of the way, here is how you would do this in Rails (that is, do what you said, not what I outlined in the paragraph above):


class CreateOrders < ActiveRecord::Migration    create_table :orders do |t|      def up        t.references :billing_address        t.references :shipping_address      end    end  end  

Here you are specifying that there are two columns in this table that will be referred to as :billing_address and :shipping_address and which hold references to another table. Rails will actually create columns called 'billing_address_id' and 'shipping_address_id' for you. In our case they will each reference rows in the Users table, but we specify that in the models, not in the migrations.


class Order < ActiveRecord::Base    belongs_to :billing_address, class_name => 'Address'    belongs_to :shipping_address, class_name => 'Address'  end  

Here you are creating a property on the Order model named :billing_address, then specifying that this property will be referencing an instance of the Address class. Rails, seeing the 'belongs_to', will look for a column in the orders table called 'billing_address_id', which we defined above, and use that to store the foreign key. Then you're doing the exact same thing for the shipping address.

This will allow you to access your Billing Address and Shipping Address, both instances of the Address model, through an instance of the Order model, like this:

@order.billing_address # Returns an instance of the Address model  @order.shipping_address.street1 # Returns a string, as you would expect  

As a side note: the 'belongs_to' nomenclature is kind of confusing in this case, since the Order doesn't belong to an Address. Ignore your intuition though; the 'belongs_to' is used on whichever thing contains the foreign key.

class Address < ActiveRecord::Base    has_many :orders_as_billing_address, :class_name => 'Order', :foreign_key => 'billing_address_id'    has_many :orders_as_shipping_address, :class_name => 'Order', :foreign_key => 'shipping_address_id'  end  

Here you are creating a property on the Address Model named :orders_as_billing_address, specifying that this property is related to the Order Model, and that the foreign key on the Order model which relates it to this property is called 'billing_address_id'. Then you are doing the same thing for :orders_as_shipping_address.

This allows you to get all the orders where an Address was used as the billing or shipping address, like so:

@address.orders_as_billing_address  @address.orders_as_shipping_address  

Doing either of these will return an array of instances of the Order model.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »