可以在Ruby on Rails中描述这种关系吗?

时间:2009-11-14 16:38:31

标签: ruby-on-rails activerecord foreign-key-relationship

这是一个可以在Ruby on Rails的ActiveRecord模型关系中描述的关系吗?

   Customer                          Address
   ===================               =========
   Billing_Address_Id  >------}
                              }---|- AddressId
   Shipping_Address_Id >------}

这样我就可以拥有如下所示的数据:

地址:

   Id | Addr           | City     | State | Zip   |
   ================================================
   1  | 123 Main       | New York | NY    | 99999 |
   2  | 200 2nd Street | New York | NY    | 99999 |
   3  | 300 3rd Street | Albany   | NY    | 99998 |
   4  | PO Box 4       | Albany   | NY    | 99998 |

客户:

   Id | Name | Billing_Address_Id | Shipping_Address_Id  |
   =======================================================
   1  | Bob  | 1                  | 1                    |
   2  | Al   | 2                  | 1                    |
   3  | Joe  | 3                  | 4                    |

我想将地址存储在自己的表中,因为数据可能会在客户之间共享(特别是送货地址)。但对于任何给定的客户,甚至只有两个地址。

我希望避免多对多的关系,除非没有别的办法。

3 个答案:

答案 0 :(得分:5)

是的,完全可以做到这一点。给定customers表,其中包含shipping_address_idbilling_address_id表的addressesCustomerclass Customer < ActiveRecord::Base belongs_to :billing_address, :class_name => 'Address' belongs_to :shipping_address, :class_name => 'Address' end 模型可能如下所示:

Address

这将允许客户引用相同的地址行以获取送货地址和帐单地址,并且还允许多个客户共享地址。

更新:在分享对此类地址的引用时,您可能需要仔细考虑如何处理地址更新。在您的示例中,Bob和Al共享相同的送货地址。现在,如果Bob更新了他的送货地址,您可能想要为Bob的新地址创建新的{{1}}记录,而不是更新现有记录,以避免更改Al的地址。有时,在这种情况下,您实际上可能想要更新两个客户的地址,但在大多数情况下,您可能不会这样做。

答案 1 :(得分:2)

给出如下的表定义:

create_table :addresses do |t|
  t.string :street
  t.string :city
  t.string :state
  t.string :zip
  t.timestamps
end

create_table :customers do |t|
  t.string     :name
  t.references :shipping_address
  t.references :billing_address
  t.timestamps
end

您可以将结算和送货地址与您的客户相关联,如下所示:

class Customer < ActiveRecord::Base
  belongs_to :shipping_address, :class_name => "Address"
  belongs_to :billing_address,  :class_name => "Address"
end

答案 2 :(得分:0)

The documentation for ActiveRecord associations has a section on has_one vs belongs_to.此外,section on has_one提到仅当其他类具有外键时才应使用此选项。因此,为了模拟你想要的东西,你可以使用。

class Address < ActiveRecord::Base
  has_one :shipto_customer, :class_name => "Customer", :foreign_key => "shipping_address_id"
  has_one :billto_customer, :class_name => "Customer", :foreign_key => "billing_address_id"
end

class Customer < ActiveRecord::Base
  belongs_to :shipping_address, :class_name => "Address"
  belongs_to :billing_address,  :class_name => "Address"
end

使用示例:

>> customer = Customer.new(:name => "John Smith",
?>     :shipping_address => Address.new(:address => "123 M St",
?>       :city => "Phoenix", :state => "AZ", :zip => "85015"),
?>     :billing_address => Address.new(:address => "555 W Main Dr",
?>       :city => "Phoenix", :state => "AZ", :zip => "85015")
>>   )
=> #<Customer id: nil, name: "John Smith", billing_address_id: nil, shipping_address_id: nil, created_at: nil, updated_at: nil>
>> customer.save
  Address Create (0.8ms)   INSERT INTO "addresses" ("address", "city", "zip", "created_at", "updated_at", "state") VALUES('555 W Main Dr', 'Phoenix', '85015', '2009-11-14 17:03:28', '2009-11-14 17:03:28', 'AZ')
  Address Create (0.2ms)   INSERT INTO "addresses" ("address", "city", "zip", "created_at", "updated_at", "state") VALUES('123 M St', 'Phoenix', '85015', '2009-11-14 17:03:28', '2009-11-14 17:03:28', 'AZ')
  Customer Create (0.2ms)   INSERT INTO "customers" ("name", "billing_address_id", "shipping_address_id", "created_at", "updated_at") VALUES('John Smith', 1, 2, '2009-11-14 17:03:28', '2009-11-14 17:03:28')
=> true
>> customer.shipping_address
=> #<Address id: 2, address: "123 M St", city: "Phoenix", state: "AZ", zip: "85015", created_at: "2009-11-14 17:03:28", updated_at: "2009-11-14 17:03:28">
>> customer.billing_address
=> #<Address id: 1, address: "555 W Main Dr", city: "Phoenix", state: "AZ", zip: "85015", created_at: "2009-11-14 17:03:28", updated_at: "2009-11-14 17:03:28">
>>