使用Squeel gem查找多个时隙

时间:2012-11-22 22:20:22

标签: ruby-on-rails ruby squeel

我的模型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。

提前致谢!

3 个答案:

答案 0 :(得分: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')
))

答案 1 :(得分:1)

你可以复制并粘贴你的ruby代码生成的SQL吗?

修改

好的,我现在明白你的问题,并且问题不明确。 如果你想保持代码可读,你应该在这种情况下使用ARel而不是squeel(至少不是为此而做的DSL)。您应该能够应用地图功能,然后使用OR加入所有内容。

答案 2 :(得分:0)

Squeel where()方法返回AR:Relation,isnt'it?

然后你应该能够链接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可能有点太多了,但试一试:)