簡體   English   中英

Rails:多態關聯,取決於類型的不同選項?

[英]Rails: polymorphic association, different options depending on type?

我正在Rails 4.1中構建飲食分析應用程序。 我有一個模型FoodEntry ,它在一個簡單的級別上具有一個quantity值,並引用一個FoodMeasure

class FoodEntry < ActiveRecord::Base
  belongs_to :food
  belongs_to :measure
end

但是,我實際上有兩種不同類型的度量,標准通用度量(杯子,茶匙,克等)和特定於食物的度量(西蘭花頭,中型香蕉,大罐頭等)。 聽起來像是多態關聯的案例吧? 例如

class FoodEntry < ActiveRecord::Base
  belongs_to :food
  belongs_to :measure, polymorphic: true # Uses measure_id and measure_type columns
end

class StandardMeasure < ActiveRecord::Base
  has_many :food_entries, as: :measure
end

class FoodMeasure < ActiveRecord::Base
  has_many :food_entries, as: :measure
end

問題是,針對食物的措施來自舊式數據庫轉儲。 這些記錄是通過food_iddescription的組合來唯一標識的-它們沒有提供單列主鍵( description不是唯一的,因為有多個食物具有相同的度量描述但數字數據不同)。 因為我正在導入Rails Postgres數據庫,所以我能夠添加代理主鍵-Rails期望的自動遞增整數id列。 但是我不想將此id用作我的FoodEntry模型中的引用,因為當(外部提供的)數據更新並且我必須重新導入時,它對於保持引用完整性保持完整性提出了很大的挑戰。 基本上,這些ids完全可以更改,因此我寧願直接引用food_iddescription

幸運的是,通過在關聯上使用范圍,在Rails中做到這一點並不困難:

class FoodEntry < ActiveRecord::Base
  belongs_to :food
  belongs_to :measure, ->(food_entry) { where(food_id: food_entry.food_id) }, primary_key: 'description', class_name: 'FoodMeasure'
  # Or even:           ->(food_entry) { food_entry.food.measures }, etc.
end

這樣會產生一個完全可以接受的查詢,如下所示:

> FoodEntry.first.measure
FoodMeasure Load (15.6ms)  SELECT  "food_measures".* FROM "food_measures"  WHERE "food_measures"."description" = $1 AND "food_measures"."food_id" = '123' LIMIT 1  [["description", "Broccoli head"]]

請注意,在這種情況下,此方法假設measure_id是字符串列(因為description是字符串)。

反觀StandardMeasure數據我的控制之下,根本不涉及Foods ,因此它使得簡單地引用非常有意義id在這種情況下,列。

因此,我的問題的症結在於:我需要一種方法讓FoodEntry僅引用一種類型的量度,就像上面我在多態關聯示例中所做的那樣。 但是,我不知道如何針對我的measure模型實現多態關聯,因為這樣看來:

  • 關聯的FoodMeasure需要通過作用域進行引用,而StandardMeasure則不需要。
  • 關聯的FoodMeasure需要通過字符串引用,而StandardMeasure則通過整數引用(並且所引用的列具有不同的名稱)。

我如何調和這些問題?


編輯:我想我應該解釋為什么我不希望使用自動編號idFoodMeasures我的外鍵FoodEntries 數據集更新后,我的計划是:

  1. 將當前food_measures表重命名為retired_food_measures (或其他名稱)。
  2. 將新的數據集導入到新的food_measures表中(具有新的自動編號ID集)。
  3. 在這兩個表之間運行retired_food_measures ,然后刪除retired_food_measures所有公共記錄,使其僅包含已退休的記錄。

如果我通過food_iddescription引用這些度量,那我將獲得好處,即食物條目會自動引用新記錄,因此將引用給定度量的任何更新的數值數據。 如果我在新的引用度量中找不到引用的度量,則可以指示我的應用程序在retired_food_measures表中進行搜索。

這就是為什么我認為使用id列會使事情變得更復雜,為了獲得相同的好處,我必須確保每個更新的記錄都收到與舊記錄相同的id ,每個新記錄都收到一個未使用的新id -before id ,並且不再使用任何已退休的id

還有一個我不想這樣做的原因:訂購。 轉儲中的記錄首先由food_id進行排序,但是任何給定food_id都按非字母順序排列,但是我想保留這些順序。 id列可以很好地實現此目的(因為在導入時按行順序分配了id),但是當id開始變得混亂時,我就失去了這一好處。

所以,是的,我確定我可以實施這些問題的解決方案,但是我不確定這樣做是否值得?

在更新(外部提供的)數據時,要保持參照完整性不變,這是一個很大的挑戰

這是一種幻想。 您完全可以控制代理人。 無論是否存在外部更新,您都可以精確地對其進行處理。

這只是您想要自己的事物新名稱的一種情況,在本例中為“度量”,其中FoodMeasures和StandardMeasures是子類型。 在所有三個模型/表中都有一個measure_id。 您可以找到許多簡化子類型約束的習慣用法,例如使用類型標記。

如果您以某種方便的方式處理外部更新,使此類對象也具有此類替代,那么您需要明確地將PutativeFoodMeasure和FoodMeasure分隔為某些超類型PutativeOrProvenFoodMeasure和/或PutativeOrProvenMeasure的子類型。

編輯:

您的更新會有所幫助。 您描述了我的所作所為。 將舊的ID映射到新的ID並不難; 加入新舊(food_id,說明),然后選擇舊ID(而不是food_id!)。 您控制ID; 與什至不存在的ID相比,重用ID有什么關系? 同上用於分類FoodMeasures; 盡你所能。 僅當您將它們與StandardMeasures混合使用時,您才需要以不同的順序訂購混合物; 但無論是否存在共享ID,您還是要這樣做。 (盡管“多態性:”可能不是最好的ID共享設計。)

度量模型提供度量; 當您知道自己有FoodMeasure或StandardMeasure時,就可以了解其特定於亞型的部分。

暫無
暫無

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

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