我的Rails应用程序中有以下模型:
class Shift < ActiveRecord::Base
has_many :schedules
scope :active, where(:active => true)
end
class Schedule < ActiveRecord::Base
belongs_to :shift
end
我希望生成所有活动班次的集合,并急切加载任何在两个给定日期之间occurs_on
的相关日程表。如果班次在这些日期之间没有时间表,则仍应在结果中返回。
基本上,我想生成等价于:
的SQLSELECT 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')
问题是happen_on过滤是在where子句中完成的,而不是在join中完成的。如果班次在该期间没有时间表,则根本不返回。
我的第二次尝试是使用joins
方法,但这会进行内连接。同样,这将删除那段没有时间表的所有班次。
我很沮丧,因为我知道我希望AREL生成的SQL,但我无法弄清楚如何使用API来表达它。任何人吗?
答案 0 :(得分: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 :(得分:1)
您可以使用SQL片段作为联接方法调用的参数:
Shift.active.joins('LEFT OUTER JOIN schedules ON schedules.occurs_on...')
答案 2 :(得分:-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(@start_date..@end_date)))
.to_sql