Rails:使用 Ransack 过滤日期和/或时间
Rails: Filter date or time or both using Ransack
我有一个 Schedule
数据库 table 有 2 列:
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
select 菜单中选择开始时间而忽略日期菜单,那么 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
如果我从日期 select 中选择一个日期,同时忽略两个时间 select 菜单,那么 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
如果我在时间 select 菜单中添加 ignore_date: true
选项,并且如果我从 select 菜单中选择开始时间,那么 Ransack 将完全忽略时间 select :
SELECT "schedules".* FROM "schedules" ORDER BY "schedules"."starts_at" ASC, "schedules"."ends_at" ASC
如果我将 include_blank: true
选项添加到两个时间 select 然后选择一个日期,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
我完全迷失在这里。感谢您的帮助。
知道了。
# 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
我有一个 Schedule
数据库 table 有 2 列:
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
select 菜单中选择开始时间而忽略日期菜单,那么 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
如果我从日期 select 中选择一个日期,同时忽略两个时间 select 菜单,那么 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
如果我在时间 select 菜单中添加 ignore_date: true
选项,并且如果我从 select 菜单中选择开始时间,那么 Ransack 将完全忽略时间 select :
SELECT "schedules".* FROM "schedules" ORDER BY "schedules"."starts_at" ASC, "schedules"."ends_at" ASC
如果我将 include_blank: true
选项添加到两个时间 select 然后选择一个日期,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
我完全迷失在这里。感谢您的帮助。
知道了。
# 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