【问题标题】:Can this relationship be described in Ruby on Rails?这种关系可以在 Ruby on Rails 中描述吗?
【发布时间】:2009-11-18 05:37:42
【问题描述】:

这种关系可以在 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                    |

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

除非没有其他办法,否则我想避免多对多关系。

【问题讨论】:

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


    【解决方案1】:

    是的,完全有可能做到这一点。给定一个 customers 表,其中有两个外键 shipping_address_idbilling_address_idaddresses 表,您的 Customer 模型可能如下所示:

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

    这将让客户为送货地址和帐单地址引用相同的地址行,并且还可以让多个客户共享地址。

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

    【讨论】:

    • 我同意您的设计评估。我的例子比我实际要做的稍微简化了一点;客户实际上是同一家庭中同一帐户的一部分。他们可能共享相同的地址,或者可能希望运送到不同的位置。
    【解决方案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
    

    【讨论】:

    • 表格设计会有所帮助。我不知道 .references “数据类型”。
    【解决方案3】:

    The documentation for ActiveRecord associations has a section on has_one vs belongs_to. 此外,section on has_one 提到仅当 other 类 具有外键时才应使用它。因此,要对您想要的模型进行建模,您可以使用。

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

    【讨论】:

    • OP希望能够在客户之间共享地址,所以Address模型中的关系应该是has_many而不是has_one关系。
    • 从 OP 的帖子中似乎不太清楚,在数据示例中,他显示了正在共享的地址,即:has_many,在代码示例中,他建议使用 has_one。然后他说他宁愿不要多对多。在我看来,共享地址是个坏主意。当客户 A 更新其当前地址以添加 zip+4 或 Apt 编号时会发生什么?
    • 是的,共享地址肯定很麻烦。将地址和客户保存在单独的表中可能是一个清晰的好主意,但在决定如何处理地址更新时,共享对地址行的引用很可能会导致问题。
    • 我试图简化我的问题示例。有问题的客户实际上是同一个家庭的一部分,因此对一个地址的更改应该为所有人更新。
    猜你喜欢
    • 2011-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多