简而言之,我遇到了一个可怕的 2(n) 查询问题。如果 n = 数据库中的技能数量,那么我的 characters#edit 表单将需要 2(n) 次查询来加载页面。它会在每个技能中选择一个 PlayerSkill(连接表),并且每个技能都会查找一次技能。
这是一些我认为与情况相关的代码。本质上,这个过程涉及的模型、视图和控制器,少了模型验证,少了我不关心的动作。
控制器:
# GET /characters/1/edit
def edit
@character = Character.find(params[:id], :include => {:player_skills => :skill})
stub_player_skills
end
private
def stub_player_skills
@skills = Skill.find(:all)
@skills.each do |skill|
if (skill.player_skills.empty?)
ps = @character.player_skills.build(:skill_id => skill.id, :name => skill.name)
end
end
end
型号:
class Character < ActiveRecord::Base
belongs_to :user
belongs_to :campaign
has_many :sheets, :dependent => :destroy
has_many :tokens, :dependent => :destroy
has_many :player_skills, :dependent => :destroy
has_many :skills, :through => :player_skills
accepts_nested_attributes_for :player_skills, :allow_destroy => true
end
令人反感的观点(HAML):
%h1
Editing Character
- form_for @character do |f|
= f.error_messages
%p
= f.label :name
%br
= f.text_field :name
%p
= f.label :race
%br
= f.text_field :race
%p
= f.label :char_class
%br
= f.text_field :char_class
%p
-f.fields_for :player_skills do |ps|
=ps.object.skill.name
=ps.text_field :level
=ps.hidden_field :skill_id
-unless ps.object.new_record?
=ps.check_box '_destroy'
=ps.label '_destroy', 'Remove'
%br
%p
= f.submit
我对这种情况的理解是,急切加载的存在是为了在(大致)一个额外的查询中获取关联。
我需要在两个区域正确应用急切加载,而我对如何做到这一点不知所措。
在 stub_player_skills 方法中,它需要创建一个 PlayerSkill 对象,假设角色还没有一个。 它可以从这里的预加载中受益,因为它循环遍历数据库中的每个技能。这就是第一个“n 查询”的来源。
然后在视图上,fields_for 循环遍历我们积累的所有 PlayerSkills,因为这里没有办法预先加载,当我调用 =ps.object.skill.name 打印出技能名称时,它会进行技能查找,这带来了第二组“n 查询”。
我主要关心的是视图层,我找不到任何文档(Rails API 或其他)说明如果您使用 fields_for 生成嵌套表单,您可以如何急切地加载关联。
感谢您的所有回复:) ~Robbie