Rails自关联问题:Item与Recipe双向关联无法同时生效
解决Item与Recipe(作为Item子类)的多对多双向关联问题
我有一个Item模型,希望将Recipe作为Item的一种类型,让它可以关联多个Item。我的ingredients表中有一条记录:(id: 1, recipe_id: 1, item_id: 2)。需要实现以下三个查询:
item.find(1).items:返回recipe_id为1的所有Item(即该配方的所有原料)item.find(1).ingredients:返回recipe_id为1的Ingredient记录item.find(2).recipes:返回item_id为2的所有Recipe(即包含该原料的所有配方)
目前我只能实现其中一个关联查询,无法同时满足三者。
现有代码
迁移文件
class CreateIngredients < ActiveRecord::Migration[7.0] def change create_table :ingredients do |t| t.references :items, null: false, foreign_key: true t.references :recipe, references: :items, foreign_key: { to_table: :items } t.timestamps end end end
Ingredient 模型
class Ingredient < ApplicationRecord belongs_to :recipe, class_name: 'Item' belongs_to :item end
Item 模型(当前版本)
has_many :ingredients has_many :items, through: :ingredients has_many :recipes, through: :ingredients
解决方案
问题出在Item模型的through关联没有明确指定方向,Rails无法区分两个反向关联。需要给每个关联指定对应的外键和源关联:
修改后的 Item 模型
class Item < ApplicationRecord # 作为配方时,关联它的原料记录 has_many :ingredients, foreign_key: :recipe_id, dependent: :destroy # 获取该配方的所有原料Item has_many :ingredient_items, through: :ingredients, source: :item # 作为原料时,关联包含它的配方记录 has_many :reverse_ingredients, class_name: 'Ingredient', foreign_key: :item_id, dependent: :destroy # 获取包含该原料的所有配方Item has_many :recipes, through: :reverse_ingredients, source: :recipe end
调整后的查询方式:
- 获取配方(id:1)的所有原料Item:
item.find(1).ingredient_items - 获取配方(id:1)的Ingredient记录:
item.find(1).ingredients - 获取原料(id:2)的所有配方:
item.find(2).recipes
关键说明:
has_many :ingredients指定foreign_key: :recipe_id,明确这条关联是从Item(配方)指向Ingredient的recipe_id字段,确保item.find(1).ingredients能正确返回该配方的原料关联记录。ingredient_items关联用source: :item指定从Ingredient的item关联获取对应Item,避免和模型名Item冲突。reverse_ingredients是反向关联,指定class_name: 'Ingredient'和foreign_key: :item_id,表示这条关联是从Item(原料)指向Ingredient的item_id字段。has_many :recipes通过reverse_ingredients关联,用source: :recipe获取所有包含该原料的配方Item。
Ingredient模型和迁移文件无需修改,已满足需求。
内容的提问来源于stack exchange,提问作者yeahNah
相关产品推荐
相关产品推荐

