Rails,解决这个n + 1的技巧?
我有一个员工视图,其中列出了所有技能,这些技能都写在我的数据库的技能表中。 对于每个员工,所有技能都会显示出来,就像希望的那样。
员工和技能彼此相关,就像许多人一样:通过联想。
class Employee < ApplicationRecord has_many :employeeskillsets, foreign_key: "employee_id" has_many :skills, through: :employeeskillsets end class Skill < ApplicationRecord has_many :employeeskillsets, foreign_key: "skill_id" has_many :employees, through: :employeeskillsets end class Employeeskillset < ApplicationRecord belongs_to :employee, foreign_key: 'employee_id' belongs_to :skill, foreign_key: 'skill_id' end
所有这些技能都显示为按钮,这些按钮用于启用/禁用该员工的特定技能(每次单击直接插入/删除,无需额外提交)。
但现在,我想在加载页面时将按钮显示为彩色。 如果已启用该技能,则按钮颜色应为绿色,否则为灰色。 这里开始我的问题:我的应用程序使用一个单独的select语句检查每个技能。 我使用以下代码:
尝试pluck
ID,然后检查include?
因为你不需要获取skills
所有属性
<% skills = @employee.skills.pluck(:id) %> <%= link_to apply_skill_employee_path(employee: @employee, skill_id: skill.id), method: :put, remote: :true do %> <% if skills.include?(skill.id) %> <%= skill.name %>
<% else %> <%= skill.name %>
<% end %>
既然skill
也是一个活跃的记录模型,你可以使用include?
关于员工的技能收集,以检查员工是否具有特定技能。
@employee.skills.include?(skill)
通过这种方式,您可以自由使用includes
条款来急切地加载员工的技能。
这不会触发附加查询
<% if @employee.skill_ids.exists?(skill.id) %>
还要避免以下行中的n+1
apply_skill_employee_path(employee: @employee, skill_id: skill.id)
确保你包括skills
@employee = Employee.includes(:skills).where(......)
Rails方式简单得多。
当您在ActiveRecord中使用has_many
宏时,它还会创建一个_ids
方法,该方法可用于添加或删除与数组的关系:
@employee.skills_ids = [1,2,3]
这也适用于与:through
选项的间接关联。
您可以将它与表单集合助手一起使用来创建select或checkbox标签:
<%= form_for(@employee) do |f| %> <%= f.label :skill_ids, 'Skills' %> <%= f.collection_check_boxes(:skills_ids, Skill.all, :id, :name) %> <% end %>
要避免额外的查询,您可以在控制器中执行左外连接:
def edit # left_outer_joins is new in Rails 5 # see https://blog.bigbinary.com/2016/03/24/support-for-left-outer-joins-in-rails-5.html @employee.left_outer_joins(:skills).find(params[:id]) end
您也不需要在控制器中使用愚蠢的额外方法来处理应作为正常更新处理的内容。 吻。