2017-03-23 7 views
0

이 방법이 있습니다. 그것의 임무는 현재 졸업생을 졸업 한 연수생 명단을 개발자에게 반환하는 것입니다. 사용자는 개발자가 원하는 기술을 필터링합니다.어떻게 리팩토링 할 수 있습니까? 또한 서버에 대한 호출 횟수를 줄이십시오.

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 개의 버튼을 클릭하여 필터링 한 결과로 표시됩니다. 사용자가 문제가 N+1 problem 같은 외모를 설명

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

'@developers.group_by {| x | x} .map {| k, v | [k, v.count]}'여기 무엇을 기준으로 그룹화합니까? – ashvin

+0

@ashvin by v.count. 나는 대부분의 기준에 먼저 부합하는 나의 견해 훈련생을 표시하고있다. like ... relevance – ORYON100

+0

'@ developers' 변수의 열을 기준으로 한 그룹을 의미합니까? v.count는 레코드별로 해당 그룹을 couting한다는 의미입니다. 개발자가로드 될 때 – ashvin

답변

1

정의 할 수 : @skills = params[:ids].nil? ? Skill.all : Skills.where(id: params[:ids])

는 그런 다음 n+1 문제에 직면했다. 이를 피하려면 eager loading associations (ELA) 또는 조인을 사용해야합니다.

수강생 개체를 ELA로 되 돌리 시려면 mapflatten을 사용할 수 있습니다.

@developers = @developers.group_by {|x| x}.map {|k, v| [k, v.count]} 
@developers.sort_by!(&:last).reverse! 

sort_by(&:last).reverse 빠르게 작동합니다

다음 당신은 좋은 부분이있다.

이 부분 : 이전 sort_by

@developers.map(&:first) 

그리고 연합 :

@developers.map! do |developer| 
    developer[0] 
end 

은 변경 될 수

@developers = @developers.sort_by(&:last).reverse.map(&:first) 

는 도움이되기를 바랍니다.

+0

감사합니다. 아래로 그리고 나는 이것을 이해하고 그것을 내가 여기 넣을 내 솔루션의 큰 부분으로 만들었다. – ORYON100

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.*') 
+0

나는 이것을 시도하고 그것은 거의 스킬 개체를 다시 제외하고 작동합니다. 나는 그것을 어떻게 연수생에게 돌려 줄 수 있는가? 나는 결과에 연수생 방법을 적용 할 수 있어야합니다. – ORYON100

+0

코드를 버리지 말고, 이것이 왜 적절한 해결책인지 설명하십시오. 누군가에게 물고기를주는 것과 물고기를 가르치는 것의 차이점입니다. "[가르쳐주세요, 단지 대답하지 마십시오] (https://meta.stackoverflow.com/a/291533/128421)"를 참조하십시오. –

+0

위의 @ ORYON100은 연수생 객체를 반환하고,'@developers.first.attributes'를 확인합니다. – ashvin

0

개발자 연수생을 통해 많은 기술을 가지고있는 경우 :

class Developer 
    has_many :trainees 
    has_many :skills, through: :trainees 
end 

그럼 당신이해야 할 수있다 :

@developers = Developer.where(skills: {id: params[:ids]}) 

또는, 당신은 아마 하나 도망 덜 사용하여 가입 할 수 : 첫째 @skills에서

@developers = Developer.where(trainees: {skill_id: params[:ids]}) 
+0

개발자 모델이 없습니다. 그 개발자는 개발자가되기 위해 부울로 트리거 될 수 있습니다. 'class Trainee 범위 : 개발자, -> {끝 ' – ORYON100

+0

이렇게 :'연수생 위치 (skill_id : params [: ids], 종료 _course : 참) ' – ReggieB

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