2014-12-05 3 views
0

주어진 다음의 모델 및 협회 :여러 범위와의 연결을 통해 has_many에서 동일한 테이블의 다중 조인을 제거하려면 어떻게합니까?

class Employee 
    has_many :positions 
    has_many :titles, :through => :positions 
    scope :is_active, -> { joins(:positions).merge(Position.is_active) } 
    scope :title_is, ->(name) { joins(:titles).merge(Title.id_or_name_is(name)) } 
end 

class Position 
    belongs_to :employee 
    belongs_to :title 
    # bool 'active' to indicate whether the position is active or not 
    scope :is_active, -> { where("active = true") } 
end 

class Title 
    has_many :positions 
    has_many :employees, :through => :positions 
    scope :id_or_name_is, ->(id_or_name) { where("titles.id = ? OR titles.name = ?", id_or_name, id_or_name) if id_or_name} 
end 

Employee.is_active 결과의 정확한 수를 반환하고 올바른 쿼리를 생성합니다. 그러나 을 시도하면 (title_id이 123이고 활성 상태 인 모든 직원을 반환하려는 경우 위치가 여러 조인이됩니다.) 활성 체크가 하나의 위치에만 적용된다는 점을 제외하면 아무 문제가 없습니다. 따라서 활성 위치와 비활성 위치 모두에서 결과 조인 : 나는 '돈 불구하고 나는 또한 where 절 positions_employees_join.active = true에 추가하는 방법이 있다면

SELECT COUNT(*) 
FROM `employees` 
    INNER JOIN `positions` ON `positions`.`employee_id` = `employees`.`id` 
    INNER JOIN `positions` `positions_employees_join` ON positions_employees_join`.`employee_id` = `employees`.`id` 
    INNER JOIN `titles` ON titles`.`id` = `positions_employees_join`.`title_id` 
WHERE positions.active = true) 
     AND (titles.id = 123 OR 
     titles.name = 123) 

나는 또한 기술적 점에 유의해야한다, 그것은뿐만 아니라, 제대로 작동 것이다 내 범위에서 어떻게 할 수 있는지 알지 못합니다.

답변

0

에서 titles 연관을 사용하지 않고 건너 뜁니다.범위. employee_instance.titles보다는 employee_instance.positions.titles를 호출 할 때 여전히 당신에게보다 효율적인 쿼리를 제공하기 때문에

scope :title_is, ->(name) { joins(:positions => :title).merge(Title.is_or_name_is(name)) } 

는 연결을 유지합니다.

joins(:positions => :title)은 범위를 지정하기 위해 joins(:positions)을 호출하는 다른 범위의 정규 조인을 사용하도록 ActiveRecord에 지시합니다.

+1

와우. 내 잘못이야. 나는'Position' 모델에서 당신의 협회를 너무 가깝게 보지 않았습니다. 의견을 반영하도록 답변을 업데이트했습니다. 감사 :) –