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语句检查每个技能。 我使用以下代码:

   

我已经尝试过使用包含,但似乎存在? 独立检查每项技能。

这里有人有一个建议,我怎么能用一个选择来解决这个问题?

在此先感谢,我希望我已经提到了一切,必要的。

编辑1:我忘了提到,我通过部分渲染(如果知道这很重要)。 这是当前在employees_controller中使用的@employee var。

 @employee = Employee.find_by(id: params[:id]) 

尝试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 

您也不需要在控制器中使用愚蠢的额外方法来处理应作为正常更新处理的内容。 吻。