2009-11-14 33 views
5

這是一種可以在Ruby on Rails的ActiveRecord模型關係中描述的關係嗎?Ruby on Rails中可以描述這種關係嗎?

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     | 

我想存儲地址在自己的表,因爲數據可以在客戶之間共享(特別是送貨地址)。但是對於任何給定的客戶,甚至只有兩個地址。

我想避免多對多的關係,除非沒有其他方法。

回答

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 
+0

表的設計會有所幫助。我沒有意識到.reference「數據類型」。 – y0mbo 2009-11-14 23:16:39

5

是的,這是完全可以做到這一點。給定一個customers表的兩個外鍵shipping_address_id和到addresses表,你Customer模型看起來是這樣的:

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

這將讓客戶參考相同的地址行運輸和賬單地址,並會也讓幾個客戶分享地址。

更新:當共享這樣的地址引用時,您可能會仔細考慮如何處理地址更新。在你的例子中,Bob和Al共享相同的送貨地址。現在,如果鮑勃更新他的送貨地址,您可能想要爲鮑勃的新地址創建一個新的記錄,而不是更新現有的記錄,以避免更改艾爾的地址。有時,在這種情況下,您實際上可能需要更新兩個客戶的地址,但在大多數情況下,您可能不需要。

+0

我同意你的設計評估。我的例子比我實際上做的要簡單一些;客戶實際上將成爲同一家庭中同一賬戶的一部分。他們可能共享相同的地址,或者可能希望將貨物運送到不同的地點。 – y0mbo 2009-11-14 23:13:00

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"> 
>> 
+0

OP希望能夠在客戶之間共享地址,因此Address模型中的關係應該是has_many而不是has_one關係。 – 2009-11-14 17:14:18

+0

從OP的帖子看來,這似乎不太清楚,在數據示例中,他顯示的地址是共享的,即:has_many,在他建議has_one的代碼示例中。然後他說他寧願不要多對多。在我看來,共享地址是一個壞主意。當客戶A更新其當前地址以添加一個zip + 4或一個Apt號碼時會發生什麼? – 2009-11-14 17:28:43

+0

是的,共享地址絕對麻煩。將地址和客戶保存在單獨的表中可能是一個明確的想法,但在決定如何處理地址更新時,共享對地址行的引用很可能會導致問題。 – 2009-11-14 17:53:22