简体   繁体   中英

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):

Migrations

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.

Models

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM