1

我有一个Planning带有start_time属性的模型。假设我想获取上午 9 点到 12 点之间或下午 6 点到 11 点之间的所有计划。

基本上我会这样做:

Planning.where do 
     (start_time >= @start_time[0]) & (start_time <= @end_time[0]) 
     | 
     (start_time >= @start_time[1]) & (start_time <= @end_time[1])
end

问题是时隙的数量各不相同......有什么想法吗?

如果有帮助,我会使用 Squeel gem。

提前致谢!

4

3 回答 3

3

你可以在街区内做任何你想做的事where;但是您必须在最后返回实际查询,因为这将用作 where 子句。

所以,给定一个这样的时间数组:

times = [ [ '09:00:00', '12:00:00' ], [ '18:00:00', '23:00:00' ] ]

这是一个详细的解决方案:

Planning.where do
  query = nil

  times.each do |a,b|
    q = (start_time >= a) & (end_time <= b)

    if query
      query |= q
    else
      query = q
    end
  end

  query
end

这是一个更聪明的解决方案:

Planning.where do
  times.map { |a,b| (start_time >= a) & (end_time <= b) }.reduce(&:|)
end

两者都生成以下 SQL:

SELECT "plannings".* FROM "plannings"
WHERE ((
  ("plannings"."start_time" >= '09:00:00' AND "plannings"."end_time" <= '12:00:00')
  OR
  ("plannings"."start_time" >= '18:00:00' AND "plannings"."end_time" <= '23:00:00')
))
于 2012-11-24T10:30:52.807 回答
1

你能复制并粘贴你的 ruby​​ 代码生成的 SQL 吗?

编辑

好的,现在我了解您的问题,并且不清楚。如果你想保持代码的可读性,你应该在这种情况下使用 ARel 而不是 squeel(至少不是为此而设计的 DSL)。您应该能够应用地图功能,然后使用 OR 连接所有内容。

于 2012-11-23T08:50:07.413 回答
0

Squeel where() 方法返回一个 AR:Relation,不是吗?

然后,您应该能够链接 where() 调用:

finder = Planing.scoped 
time_slots.each do |start_time, end_time|
    finder = finder.where{(start_time >= my{start_time}) & (start_time <= my{end_time}) }
end

我没有尝试过这段代码,但我看不出它为什么不起作用

编辑:正如您所说,这会将条件与 AND 联系起来,而不是 OR

你可以试试以下吗?

Planning.where do 
    time_slots.inject(false) do |memo, time_slot| 
        memo | (start_time >= time_slot.first) & (start_time <= time_slot.last)
    end
end 

使用 squeel 的 instance_eval 可能有点太神奇了,但试一试:)

于 2012-11-23T08:31:25.547 回答