我有一个包含2列的Schedule
db表:
t.datetime "starts_at"
t.datetime "ends_at"
当用户创建计划时,相同的日期将保存在这两列中:
starts_at: 2015-08-22 16:00:00 UTC
ends_at: 2015-08-22 16:30:00 UTC
在Schedule#index
视图中,我想展示一个可以执行以下三项操作的过滤器:
starts_at
&的时间过滤所有时间表忽略日期时ends_at
starts_at
&中的日期过滤所有日程安排ends_at
而忽视时间starts_at
&的日期和时间过滤所有日程安排。 ends_at
我的代码:
# Schedule controller
def index
@q = Schedule.ransack(params[:q])
@q.sorts = ['starts_at asc', 'ends_at asc'] if @q.sorts.empty?
@schedules = @q.result.where('starts_at >= ?', Time.zone.today)
end
# view
<%= search_form_for @q do |f| %>
<%= f.time_select :starts_at_gteq, ampm: true, default: { hour: '07' } %>
<%= f.time_select :ends_at_lteq, ampm: true, default: { hour: '23' } %>
<%= f.select :starts_at_eq, options_for_select([
['Today', Time.zone.today],
['Tomorrow', Time.zone.tomorrow],
[(Time.zone.today + 2).strftime("%d %b"), Time.zone.today + 2],
[(Time.zone.today + 3).strftime("%d %b"), Time.zone.today + 3],
[(Time.zone.today + 4).strftime("%d %b"), Time.zone.today + 4],
[(Time.zone.today + 5).strftime("%d %b"), Time.zone.today + 5],
[(Time.zone.today + 6).strftime("%d %b"), Time.zone.today + 6]
]), include_blank: true %>
...
此代码存在的问题是,如果我在忽略日期菜单时从starts_at
选择菜单中选择开始时间,那么Ransack将尝试使用今天的日期进行过滤:
SELECT "schedules".* FROM "schedules" WHERE ("schedules"."starts_at" >= '2015-08-18 16:00:00.000000' AND "schedules"."ends_at" <= '2015-08-18 23:00:00.000000') ORDER BY "schedules"."starts_at" ASC, "schedules"."ends_at" ASC
如果我从日期选择中选择日期而忽略两个时间选择菜单,那么Ransack将执行此操作:
SELECT "schedules".* FROM "schedules" WHERE ("schedules"."starts_at" = '2015-08-22 00:00:00.000000' AND "schedules"."starts_at" >= '2015-08-18 07:00:00.000000' AND "schedules"."ends_at" <= '2015-08-18 23:00:00.000000') ORDER BY "schedules"."starts_at" ASC, "schedules"."ends_at" ASC
如果我在时间选择菜单中添加ignore_date: true
选项,如果我从选择菜单中选择一个开始时间,那么Ransack将完全忽略选择的时间:
SELECT "schedules".* FROM "schedules" ORDER BY "schedules"."starts_at" ASC, "schedules"."ends_at" ASC
如果我同时添加include_blank: true
选项,然后选择日期,Ransack将使用上午12点的日期和时间进行过滤:
SELECT "schedules".* FROM "schedules" WHERE "schedules"."starts_at" = '2015-08-22 00:00:00.000000' ORDER BY "schedules"."starts_at" ASC, "schedules"."ends_at" ASC
我完全迷失在这里。谢谢你的帮助。
答案 0 :(得分:0)
知道了。
# Schedule model
ransacker :start_date, type: :date do
Arel.sql('starts_at::date') # filter only the date from starts_at attribute
end
ransacker :start_time, type: :time do
Arel.sql('starts_at::time') # filter only the time from starts_at attribute
end
ransacker :end_time, type: :time do
Arel.sql('ends_at::time') # filter only the time from ends_at attribute
end
# view
<%= search_form_for @q do |f| %>
<%= f.time_select :start_time_gteq, ampm: true, default: { hour: '07' } %>
<%= f.time_select :end_time_lteq, ampm: true, default: { hour: '23' } %>
<%= f.select :start_date_eq, options_for_select([
['Today', Time.zone.today],
['Tomorrow', Time.zone.tomorrow],
[(Time.zone.today + 2).strftime("%d %b"), Time.zone.today + 2],
[(Time.zone.today + 3).strftime("%d %b"), Time.zone.today + 3],
[(Time.zone.today + 4).strftime("%d %b"), Time.zone.today + 4],
[(Time.zone.today + 5).strftime("%d %b"), Time.zone.today + 5],
[(Time.zone.today + 6).strftime("%d %b"), Time.zone.today + 6]
], @q.start_date_eq), include_blank: true %>
...
SQL查询的外观如下:
SELECT "schedules".* FROM "schedules" WHERE (starts_at::date = '2015-08-22' AND starts_at::time >= '2015-08-19 12:15:00.000000' AND ends_at::time <= '2015-08-19 16:45:00.000000') AND (starts_at >= '2015-08-19') ORDER BY "schedules"."starts_at" ASC, "schedules"."ends_at" ASC