我正在Rails 4.1中構建一個飲食分析應用程序。我有一個模型,FoodEntry
,其中一個簡單的級別都有一個quantity
值並參照Food
和Measure
:Rails:多態關聯,不同的選項取決於類型?
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
唯一標識 - 它們未提供單列主鍵(由於有多種食物具有相同的測量描述但數字數據不同,因此它們本身並不是唯一的)。因爲我正在導入到Rails Postgres數據庫,所以我可以添加一個代理主鍵 - Rails期望的自動遞增整數id
列。但我不想在我的FoodEntry
模型中使用這個id
作爲參考,因爲當(外部提供的)數據被更新並且我不得不重新導入時,它對保持參考完整性保持不變是一個相當大的挑戰。基本上,這些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
中的任何常見記錄,因此它只包含退役記錄。
如果我引用的food_id
和description
這些措施,這樣,我得到的食物條目自動指向新的記錄,因此任何更新的數值數據爲某項措施的好處。如果在新表中找不到引用的度量值,我可以指示我的應用程序在retired_food_measures
表中搜索。
這就是爲什麼我認爲使用id
列會使事情變得更加複雜,爲了得到我必須確保每一個更新的記錄收到了同樣的id
與舊相同的好處,每一個新的紀錄接到新的未使用 - 在id
之前,並且任何退役的id
不再使用。
還有一個原因,我不想這樣做:排序。轉儲中的記錄首先按food_id
排序,但是對於任何給定的food_id
,這些度量標準都是非字母表,但仍然是我想保留的邏輯順序。 id
列可以優雅地服務於此目的(因爲id在導入時按行順序分配),但是當id開始混淆時,我失去了這種好處。
所以是的,我相信我可以實施這些問題的解決方案,但我不確定這是否值得的好處?
另請參見:[數據庫表的最佳設計是什麼,可以由兩個不同的資源擁有,因此需要兩個不同的外鍵?](http://stackoverflow.com/a/13317463/533120) –