避免在具有不同关系的轨道 STI 上进行 n+1 查询



假设我有以下模型:

class Building < ActiveRecord::Base
has_many :rooms
has_many :training_rooms, class_name: 'TrainginRoom', source: rooms
has_many :computers, through: :training_rooms
end
class Computer < ActiveRecord::Base
belongs_to :room
end
class Room < ActiveRecord::Base
belongs_to :building
end
class Office < Room
end
class TrainingRoom < Room
has_many :computers
end

我们还假设我遵循 jsonapi 规范并使用包含的顶级成员在单个 http 调用中呈现每个相关对象。

所以建筑物/表演看起来像这样:

json.data do
json.id building.id
json.type building.type
json.attributes do
# render the attributes
end
json.relationships do
# render the relationships
end
end
json.included.do
json.array! building.rooms.each do |room|
json.type room.type
json.id  room.id
json.attributes do
# render the attribtues
end
json.relationships do |room|
# render included member's relationships
# N+1 Be here
end
end
end

我无法急切地从包含的成员加载关系,因为它并不存在于数组的所有成员上。

例如,在控制器中:

@building = Building.eager_load(
{ rooms: :computers }
).find(params[:id])

如果房间关系中有办公室,则不起作用,因为它没有计算机关系。

@building = Building.eager_load(
:rooms,
traning_rooms: :computers
).find(params[:id])

也不起作用,因为培训室关系提供对要旁加载的计算机的访问,但不直接在渲染代码中访问,因此是无用的缓存。

此外,我尝试将默认范围应用于培训室以预先加载计算机关联,但这也没有产生预期的影响。

此时我唯一能想到的就是将计算机关系应用于 Room 类,但我真的不想这样做,因为只有培训室才应该有计算机。

我很想听听任何想法。

由于计算机模型中没有training_room_id,因此在定义关系时必须明确提及foreign_key

class TrainingRoom < Room
has_many :computers, foreign_key: :room_id
end

现在,您将能够急切地加载记录:

@building = Building.eager_load({ training_rooms: :computers }).where(id: params[:id])

希望对您有所帮助!

相关内容

  • 没有找到相关文章

最新更新