ARel: добавить дополнительные условия к внешнему соединению - PullRequest
1 голос
/ 25 января 2012

В моем приложении Rails есть следующие модели:

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')

Проблема состоит в том, что фильтрация происходит_ в выполняется в предложении where, а не в объединении. Если у смены нет расписаний за этот период, она вообще не возвращается.

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

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

Ответы [ 3 ]

6 голосов
/ 17 апреля 2013

Вы можете попробовать довольно сырой 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 голос
/ 25 января 2012

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

Shift.active.joins('LEFT OUTER JOIN schedules ON schedules.occurs_on...')
0 голосов
/ 27 марта 2016

Вы можете построить необработанный 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(@start_date..@end_date)))
      .to_sql
...