簡體   English   中英

在Rails中,如何將一個模型兩次連接到一個多態屬於的另一個模型?

[英]In Rails, how to connect a model twice to another model that it polymorphically belongs_to?

我正在嘗試確定在Rails 4中設置以下架構和關聯的適當方法:

Business
  company_name
  ->1 street_address (Address)
  ->0..1 mailing_address (Address)
  ->0..n employees (Employee)

Employee
  first_name
  last_name
  birthday
  ->0..n addresses (Address)

Address
  street
  city
  state
  zip
  ->1 resource (Business or Employee or potentially something else in the future)

這里的主要目標是:

  1. 能夠檢索任意地址並依次找到其所屬的資源(可能是企業或雇員)
  2. 將每個公司的一個地址指定為“街道地址”,還可以將另一個地址指定為“郵寄地址”
  3. 允許每個企業擁有多個員工,每個員工可能具有其他不同的地址(家庭住址等)。
  4. 允許其他未來資源(迄今未知)也具有關聯的地址

請注意,一個地址既可以屬於一個公司(充當該公司的街道地址或郵寄地址),也可以屬於一個雇員(一個雇員可以有多個地址)。 對我而言,這意味着多態關系,而我在Rails中實現此目標的第一步是這樣的:

class Business < ActiveRecord::Base
  has_one :street_address, class_name: 'Address', as: :resource, 
                           inverse_of: :resource, dependent: :destroy
  has_one :mailing_address, class_name: 'Address', as: :resource, 
                            inverse_of: :resource, dependent: :destroy
  has_many :business_employees, inverse_of: :business, dependent: :destroy
  has_many :employees, through: :business_employees
end

class BusinessEmpoloyee < ActiveRecord::Base
  belongs_to :business
  belongs_to :employee
end

class Employee < ActiveRecord::Base
  has_many :business_employees, inverse_of: :employee, dependent: :destroy
  has_many :businesses, through: :business_employees
  has_many :addresses, as: :resource, inverse_of: :resource, dependent: :destroy
end

class Address < ActiveRecord::Base
  belongs_to :resource, polymorphic: true
end

但是,這沒有達到預期的效果。 商家的街道地址和郵寄地址總是返回相同的值。 例如:

2.1.2 :001 > b = Business.create(company_name: 'Test Business')

2.1.2 :002 > b.street_address = Address.create(street: '123 Main St', city: 'San Francisco', state: 'CA')

2.1.2 :003 > b.mailing_address = Address.create(street: 'P.O. Box 123', city: 'New York', state_code: 'NY')

2.1.2 :004 > b2 = Business.find_by_company_name('Test Business')
  Business Load (1.2ms)  SELECT  "businesses".* FROM "businesses"  WHERE "businesses"."company_name" = 'Test Business' LIMIT 1
 => #<Business id: 1168, company_name: "Test Business", street_address_id: nil, mailing_address_id: nil, created_at: "2014-09-04 19:57:14", updated_at: "2014-09-04 19:57:14"> 

2.1.2 :005 > b2.mailing_address
  Address Load (0.5ms)  SELECT  "addresses".* FROM "addresses"  WHERE "addresses"."resource_id" = $1 AND "addresses"."resource_type" = $2 LIMIT 1  [["resource_id", 1168], ["resource_type", "Business"]]
 => #<Address id: 1186, resource_id: 1168, resource_type: "Business", street: "P.O. Box 123", city: "New York", state: "NY", zip: nil, created_at: "2014-09-04 19:57:56", updated_at: "2014-09-04 19:57:56"> 

2.1.2 :006 > b2.street_address
  Address Load (0.5ms)  SELECT  "addresses".* FROM "addresses"  WHERE "addresses"."resource_id" = $1 AND "addresses"."resource_type" = $2 LIMIT 1  [["resource_id", 1168], ["resource_type", "Business"]]
 => #<Address id: 1186, resource_id: 1168, resource_type: "Business", street: "P.O. Box 123", city: "New York", state: "NY", zip: nil, created_at: "2014-09-04 19:57:56", updated_at: "2014-09-04 19:57:56"> 

當然,這確實是有道理的-業務部門應該如何知道將哪個地址用於哪個地址值?

那么,既然如此,我如何捕捉到這里所描述的關系有什么建議?

經驗法則:關系被寫入belongs的模型中。 如果為一個模型指定兩個指向同一模型的關聯,則它們實際上將是相同的,因為只有一種歸屬方式:具有某個模型的resource_idresource_type

您需要在“所屬”中添加另一個參數,以便過濾“屬於哪種”。 一種相對標准的方法是單表繼承(STI)( 我碰巧寫過有關如何使用它的方法 ),其工作方式如下:您向Address添加一個type:string:index列,並創建一個繼承自它的新類Address ,例如MailingAddress

class MailingAddress < Address
end

大多數情況下,它應該為空,它繼承自Address甚至存儲的所有內容:存儲在同一張表中,但可以通過type="MailingAddress"進行區分,當您從數據庫查詢此類的實例時,該類型將自動添加。 但是,當您查詢Address es時,根據繼承原理,您還將獲得MailingAddress es。

執行此操作的其他方法涉及相似的內容:添加另一列以從所有其他地址中過濾出郵件地址。 即使RDBMS如此之快,字符串也不是最快的比較對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM