【发布时间】:2014-08-24 01:06:54
【问题描述】:
我正在 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 列。但是我不想在我的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 列是非常有意义的。 p>
所以我的问题的症结在于:我需要一种方法让FoodEntry 仅引用一种类型的度量,就像我在上面制作的多态关联示例中那样。但是我不知道如何针对我的measure 模型实现多态关联,因为就目前而言:
- 关联的
FoodMeasure需要通过范围引用,而StandardMeasure则不需要。 - 关联的
FoodMeasure需要通过字符串引用,而StandardMeasure需要通过整数引用(并且被引用的列具有不同的名称)。
如何协调这些问题?
编辑:我想我应该解释一下为什么我不想在FoodMeasures 上使用自动编号id 作为我在FoodEntries 中的外键。当数据集更新时,我的计划是:
- 将当前的
food_measures表重命名为retired_food_measures(或其他)。 - 将新数据集导入到新的
food_measures表中(使用新的自动编号 ID 集)。 - 在这两个表之间运行一个连接,然后删除
retired_food_measures中的所有公共记录,这样它就只有退休的记录了。
如果我通过food_id 和description 引用这些度量,那么我将获得食物条目自动引用新记录以及因此给定度量的任何更新数字数据的好处。如果在新表中找不到引用的度量,我可以指示我的应用程序在 retired_food_measures 表中进行搜索。
这就是为什么我认为使用id 列会使事情变得更复杂,为了获得相同的好处,我必须确保每条更新的记录都收到与旧记录相同的id,每条新记录记录收到了一个新的 not-used-before id,并且任何已停用的 id 将不再使用。
我不想这样做还有另一个原因:订购。转储中的记录首先按food_id 排序,但是任何给定food_id 的度量都是非字母顺序但我想保留的逻辑顺序。 id 列可以很好地达到这个目的(因为 id 在导入时按行顺序分配),但是当 id 开始被弄乱时,我就失去了这个好处。
所以是的,我确信我可以针对这些问题实施解决方案,但我不确定这样做是否值得?
【问题讨论】:
标签: ruby-on-rails activerecord database-design ruby-on-rails-4 model