2012-01-25 3 views
1

У меня есть следующие модели в моем приложении Rails: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 делается где положение, а не в соединение. Если сдвиг не имеет графиков в этот период, он не возвращается вообще.

Моя вторая попытка состояла в том, чтобы использовать метод joins, но это делает внутреннее соединение. Опять же, это снизит все смены, у которых нет графиков для этого периода.

Я расстроен, потому что я знаю SQL, я хочу, чтобы AREL генерировал, но я не могу понять, как выразить его с помощью API. Кто угодно?

ответ

1

Вы можете использовать фрагмент SQL в качестве аргумента вашего JOINS вызова метода:

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

вы можете попробовать некоторые довольно сырой AREL. Отказ от ответственности: у меня не было фактических классов Schedule и Shift, поэтому я не смог проверить это правильно, но я использовал некоторые существующие таблицы для устранения неполадок на своей машине.

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

Вы можете создать запрос сырой SQL, используя Arel следующим образом:

@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 
Смежные вопросы