Rails model and DB schema with two foreign keys from one table

I am developing an ordering model for a Rails application. I am trying to submit an order that has BillToAddressId and ShipToAddressId as foreign keys from the Address table.

Below is a table of addresses:

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 DB / migrate for Order and Address.

It would be great if someone could help me build the model and port the script.

+2


a source to share


2 answers


You can do it like this

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 conversion Column name "ShipToAddressId" must be "ship_to_address_id"

+4


a source


Important: You should not allow users to delete or change addresses , given how you model the relationship between orders and addresses. If you do this, billing or shipping addresses in Orders that have already taken place may be changed or deleted, which is very bad. To avoid this, allow users to add new addresses or mark existing ones as inactive.

With that in mind, here's how you would do it in Rails (i.e. do what you said, not what I outlined in the paragraph above):

Migration

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

      

Here you indicate that this table has two columns, which will be named: billing_address and: shipping_address, which contain links to another table. Rails will actually create columns for you named "billing_address_id" and "shipping_address_id". In our case, each row of links will be listed in the "Users" table, but we will indicate that in models, not migrations.

Models

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

      

Here, you create a property in the Order model named: billing_address, and then specify that this property will reference an instance of the Address class. Rails, seeing "ownership", will look for a column in the orders table named "billing_address_id" that we defined above and use that to store the foreign key. Then you do the same for the shipping address.



This will allow you to access your billing and shipping address, both instances of the Address model, through an instance of the order model, for example:

@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 item 'owned by_to' is confusing in this case because the order does not belong to the address. Ignore your intuition; 'belongs_to' is used depending on what the foreign key contains.

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 create a property in the address model named: orders_as_billing_address, specifying that this property is associated with the order model, and that the foreign key of the Order model that binds it to this property is called "billing_address_id". Then you do the same for: orders_as_shipping_address.

This allows you to receive all orders where the address was used as an invoicing or shipping address, for example:

@address.orders_as_billing_address
@address.orders_as_shipping_address

      

Doing any of these will return an array of Order model instances.

0


a source







All Articles