[英]Rails: polymorphic association, different options depending on type?
我正在Rails 4.1中構建飲食分析應用程序。 我有一個模型FoodEntry
,它在一個簡單的級別上具有一個quantity
值,並引用一個Food
和Measure
:
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_id
和description
的組合來唯一標識的-它們沒有提供單列主鍵( description
不是唯一的,因為有多個食物具有相同的度量描述但數字數據不同)。 因為我正在導入Rails Postgres數據庫,所以我能夠添加代理主鍵-Rails期望的自動遞增整數id
列。 但是我不想將此id
用作我的FoodEntry
模型中的引用,因為當(外部提供的)數據更新並且我必須重新導入時,它對於保持引用完整性保持完整性提出了很大的挑戰。 基本上,這些ids
完全可以更改,因此我寧願直接引用food_id
和description
。
幸運的是,通過在關聯上使用范圍,在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
則通過整數引用(並且所引用的列具有不同的名稱)。 我如何調和這些問題?
編輯:我想我應該解釋為什么我不希望使用自動編號id
上FoodMeasures
我的外鍵FoodEntries
。 數據集更新后,我的計划是:
food_measures
表重命名為retired_food_measures
(或其他名稱)。 food_measures
表中(具有新的自動編號ID集)。 retired_food_measures
,然后刪除retired_food_measures
所有公共記錄,使其僅包含已退休的記錄。 如果我通過food_id
和description
引用這些度量,那我將獲得好處,即食物條目會自動引用新記錄,因此將引用給定度量的任何更新的數值數據。 如果我在新的引用度量中找不到引用的度量,則可以指示我的應用程序在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.