多个外键引用RoR中的同一个表

我希望客户引用两个地址模型,一个用于帐单地址,另一个用于送货地址。 据我了解,外键由其名称决定,如_id。 显然我不能命名两行address_id(引用Address表)。 我该怎么办?

create_table :customers do |t| t.integer :address_id t.integer :address_id_1 # how do i make this reference addresses table? # other attributes not shown end 

这听起来像是一个has_many关系 – 把customer_id放在Address表中。

 Customer has_many :addresses Address belongs_to :customer 

您还可以在assoc声明中提供外键和类

 Customer has_one :address has_one :other_address, foreign_key => "address_id_2", class_name => "Address" 

对于刚接触Rails的人来说,这可能会让人感到困惑(正如我最近的那样),因为答案的某些部分发生在您的迁移中,而某些部分发生在您的模型中。 此外,您实际上想要模拟两个单独的事物:

  1. 地址属于单个客户,每个客户都有许多地址。 在您的情况下,这将是1或2个地址,但我鼓励您考虑客户可能有多个送货地址的可能性。 例如,我在Amazon.com上有3个单独的送货地址。

  2. 另外,我们希望模拟每个客户都有帐单邮寄地址和送货地址这一事实,如果您允许多个送货地址,则可能改为默认送货地址。

这是你如何做到这一点:

迁移

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

在这里,您指定此表中有两列将被称为:billing_address和:shipping_address,其中包含对另一个表的引用。 Rails实际上会为您创建名为“billing_address_id”和“shipping_address_id”的列。 在我们的例子中,他们将每个引用Addresses表中的行,但我们在模型中指定,而不是在迁移中。

 class CreateAddresses < ActiveRecord::Migration create_table :addresses do |t| def up t.references :customer end end end 

在这里,您还要创建一个引用另一个表的列,但最后省略了“_id”。 Rails将为您处理这个问题,因为它会看到您有一个表“客户”,它与列名相匹配(它知道多个)。

我们向客户迁移添加“_id”的原因是因为我们没有“billing_addresses”或“shipping_addresses”表,因此我们需要手动指定整个列名。

楷模

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

在这里,您将在Customer模型上创建一个名为:billing_address的属性,然后指定此属性与Address类相关。 看到'belongs_to'的Rails将在customers表中查找名为'billing_address_id'的列,我们在上面定义了该列,并使用该列存储外键。 然后你正在为送货地址做同样的事情。

这将允许您通过Customer模型的实例访问“地址”模型的两个实例的“帐单地址”和“送货地址”,如下所示:

 @customer.billing_address # Returns an instance of the Address model @customer.shipping_address.street1 # Returns a string, as you would expect 

作为旁注:在这种情况下,'belongs_to'命名法有点令人困惑,因为地址属于客户,而不是相反。 但是,忽略你的直觉; 'belongs_to'用于包含外键的任何东西,在我们的例子中,正如您将看到的, 这两种模型都是 。 哈! 如何混淆?

最后,我们指定客户有许多地址。 在这种情况下,我们不需要指定与此属性相关的类名,因为Rails足够聪明,可以看到我们有一个匹配名称的模型:'Address',我们将在一秒钟内得到它。 这允许我们通过执行以下操作获取所有客户地址的列表:

 @customer.addresses 

这将返回Address模型的一组实例,无论它们是计费还是送货地址。 说到地址模型,这是看起来像:

 class Address < ActiveRecord::Base belongs_to :customer end 

在这里,你完成了与Customer模型中'belongs_to'行完全相同的事情,除了Rails为你做了一些魔术; 查看属性名称('customer'),它会看到'belongs_to'并假设此属性引用具有相同名称的模型('Customer')并且地址表上有匹配的列('customer_id') 。

这允许我们访问地址所属的客户,如下所示:

 @address.customer # Returns an instance of the Customer model @address.customer.first_name # Returns a string, as you would expect 

由于托比,我想出了如何做到这一点:

 class Address < ActiveRecord::Base has_many :customers end 
 class Customer < ActiveRecord::Base belongs_to :billing_address, :class_name => 'Address', :foreign_key => 'billing_address_id' belongs_to :shipping_address, :class_name => 'Address', :foreign_key => 'shipping_address_id' end 

customers表包括shipping_address_id和billing_address_id列。

这基本上是一个has_two关系。 我发现这个post也很有帮助。

我有同样的问题并解决了这个问题:

 create_table :customers do |t| t.integer :address_id, :references => "address" t.integer :address_id_1, :references => "address" # other attributes not shown end