2012-01-25 4 views
1

나는 내 레일 응용 프로그램에서 다음과 같은 모델이 있습니다ARel : 외부 조인에 추가 조건을 추가

class Shift < ActiveRecord::Base 
    has_many :schedules 
    scope :active, where(:active => true) 
end 

class Schedule < ActiveRecord::Base 
    belongs_to :shift 
end 

내가 모든 활성 변화와 열망로드 occurs_on 두 사이에있는 모든 관련 일정의 컬렉션을 생성 할 주어진 날짜. 근무일에 해당 날짜 사이에 일정이 없으면 결과에 결과가 반환되어야합니다.

기본적으로 내가하는 SQL 동등한 생성 할 :

SELECT shifts.*, schedules.* 
FROM shifts 
    LEFT JOIN schedules ON schedules.shift_id = shifts.id 
    AND schedules.occurs_on BETWEEN '01/01/2012' AND '01/31/2012' 
WHERE shifts.active = 't'; 

내 첫 번째 시도를했다 :

Shift.active.includes(:schedules).where("schedules.occurs_on BETWEEN '01/01/2012' AND '01/31/2012') 

문제는 occurs_on 필터링 where 절에서 수행하고,하지에 있는지 조인 해당 기간에 근무 시간에 일정이 없으면 전혀 반환되지 않습니다.

내 두 번째 시도는 joins 메서드를 사용했지만 내부 조인을 수행했습니다. 다시 말하지만,이 기간 동안 일정이없는 모든 교대가 삭제됩니다.

AREL을 생성하는 SQL을 알고 있기 때문에 좌절감을 느낍니다.하지만 API로 표현하는 방법을 알 수 없습니다. 누군가?

답변

1

당신은 당신의 조인 메소드 호출의 인수로 SQL 조각을 사용할 수 있습니다

Shift.active.joins('LEFT OUTER JOIN schedules ON schedules.occurs_on...') 
6

당신은 꽤 원시 AREL을 시도 할 수 있습니다. 면책 조항 : 나는 실제 ScheduleShift 클래스를 가지지 않았으므로이를 제대로 테스트하지 못했지만 기존 테이블을 사용하여 내 컴퓨터에서 문제를 해결했습니다. 다음과 같이

on = Arel::Nodes::On.new(
    Arel::Nodes::Equality.new(Schedule.arel_table[:shift_id], Shift.arel_table[:id]).\ 
    and(Arel::Nodes::Between.new(
    Schedule.arel_table[:occurs_on], 
    Arel::Nodes::And.new(2.days.ago, Time.now) 
)) 
) 
join = Arel::Nodes::OuterJoin.new(Schedule.arel_table, on) 
Shift.joins(join).where(active: true).to_sql 
-1

당신은 Arel를 사용하여 원시 SQL 쿼리를 생성 할 수 있습니다 :

@start_date 
@end_date 

@shift = Shift.arel_table 
@schedule = Schedule.arel_table 

@shift.join(@schedule) 
     .on(@schedule[:shift_id].eq(@shift[:id]) 
       .and(@schedule[:occurs_on].between(@[email protected]_date))) 
     .to_sql