这是控制器方法:
def filter
@skills = Skill.all
@developers = []
unless params[:ids].nil?
params[:ids].each do |skill|
skill = @skills.find(skill)
skill.trainees.each do |developer|
@developers << developer
end
end
end
if @developers.empty?
@developers = Trainee.developers.all
else
@developers = @developers.group_by {|x| x}.map {|k, v| [k, v.count]}
@developers.sort_by!(&:last).reverse!
@developers.map! do |developer|
developer[0]
end
end
respond_to do |format|
format.js {}
end
end
目前,同样的方法是按照我想要的次数命中服务器。由于我单击11个按钮进行过滤,因此显示下面的服务器日志。可以是1或5或20,具体取决于用户要查找的内容
Processing by SkillsController#filter as */*
Parameters: {"ids"=>["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]}
Skill Load (0.6ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 1 LIMIT 1
Trainee Load (0.6ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 1
Skill Load (0.4ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 2 LIMIT 1
Trainee Load (0.6ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 2
Skill Load (0.3ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 3 LIMIT 1
Trainee Load (1.3ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 3
Skill Load (6.1ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 4 LIMIT 1
Trainee Load (0.6ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 4
Skill Load (0.3ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 5 LIMIT 1
Trainee Load (0.9ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 5
Skill Load (2.6ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 6 LIMIT 1
Trainee Load (2.0ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 6
Skill Load (4.2ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 7 LIMIT 1
Trainee Load (0.9ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 7
Skill Load (1.2ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 8 LIMIT 1
Trainee Load (3.0ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 8
Skill Load (0.3ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 9 LIMIT 1
Trainee Load (0.8ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 9
Skill Load (2.1ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 10 LIMIT 1
Trainee Load (0.6ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 10
Skill Load (0.3ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 11 LIMIT 1
Trainee Load (0.8ms) SELECT `trainees`.* FROM `trainees` INNER JOIN `mastered_skills` ON `trainees`.`id` = `mastered_skills`.`trainee_id` WHERE `mastered_skills`.`skill_id` = 11
Rendering skills/filter.js.haml
Skill Load (0.7ms) SELECT `skills`.* FROM `skills` INNER JOIN `mastered_skills` ON `skills`.`id` = `mastered_skills`.`skill_id` WHERE `mastered_skills`.`trainee_id` = 5
Skill Load (0.5ms) SELECT `skills`.* FROM `skills` INNER JOIN `mastered_skills` ON `skills`.`id` = `mastered_skills`.`skill_id` WHERE `mastered_skills`.`trainee_id` = 2728
Skill Load (0.6ms) SELECT `skills`.* FROM `skills` INNER JOIN `mastered_skills` ON `skills`.`id` = `mastered_skills`.`skill_id` WHERE `mastered_skills`.`trainee_id` = 10
答案 0 :(得分:1)
优化这部分:
@skills = Skill.all
@developers = []
unless params[:ids].nil?
params[:ids].each do |skill|
skill = @skills.find(skill)
skill.trainees.each do |developer|
@developers << developer
end
end
end
要:
@developers = Skill.where(id: params[:ids]).joins(:trainees).select('trainees.*')
答案 1 :(得分:1)
首先@skills
可以定义为:
@skills = params[:ids].nil? ? Skill.all : Skills.where(id: params[:ids])
然后你面临n+1
问题。为避免这种情况,您必须使用eager loading associations(ELA)或加入。
要使用ELA返回受训者对象,您可以使用map
和flatten
。
接下来你有一个很好的部分:
@developers = @developers.group_by {|x| x}.map {|k, v| [k, v.count]}
@developers.sort_by!(&:last).reverse!
sort_by(&:last).reverse
效果很快。
这部分:
@developers.map! do |developer|
developer[0]
end
可以更改为:
@developers.map(&:first)
与之前的sort_by
联合起来:
@developers = @developers.sort_by(&:last).reverse.map(&:first)
希望它有所帮助。
答案 2 :(得分:0)
所描述的问题看起来像N+1 problem
。渴望加载关联可能会有所帮助:http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
答案 3 :(得分:0)
如果开发人员通过学员获得许多技能:
class Developer
has_many :trainees
has_many :skills, through: :trainees
end
然后你应该能够做到:
@developers = Developer.where(skills: {id: params[:ids]})
或者,您可以使用以下方法减少一次加入:
@developers = Developer.where(trainees: {skill_id: params[:ids]})
答案 4 :(得分:0)
使用来自@idej的大部分解决方案,我现在已经将我的代码变为更好的状态。我认为它可以更简化,但我很高兴。欢迎任何更多的答案
def filter
@skills = params[:ids].nil? ? Skill.all : Skill.where(id: params[:ids])
@developers = @skills.inject([]) do |result, skill|
result << skill.trainees
end
@developers = @developers.flatten.group_by {|x| x}.map {|k, v| [k, v.count]}
@developers.sort_by!(&:last).reverse!.map!(&:first)
respond_to do |format|
format.js
end
end