在 Rails 中,您想使用 Time.zone.parse 正确处理时区。
我会用一个虚拟模型来处理这个任务。
# custom validator for dates
class DateValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value.try(:acts_like_time?) || value.try(:acts_like_date?)
record.errors.add attribute, 'is not a valid date'
end
end
end
# call this whatever you want
class Query
include ActiveModel::Model
attr_accessor :from_date, :to_date
validates :from_date, presence: true, date: true
validates :to_date, presence: true, date: true
def from_date=(value)
@from_date = convert_to_time(value)
end
def to_date=(value)
@to_date = convert_to_time(value)
end
def date_range
@from_date..@to_date
end
private
def convert_to_time(value)
return value if value.try(:acts_like_time?)
if value.try(:acts_like_string?)
begin
Time.zone.parse(value)
rescue ArgumentError
nil
end
end
end
end
但您实际上并不需要重新发明处理日期属性和验证它们的轮子,因为有很多 gem 可以处理这些,例如 validates_timeliness。
这可能看起来有点矫枉过正,但您可以像处理控制器中的任何资源一样处理它:
# this is just a simplefied example of filtering a resource
class FoosController < ApplicationController
def index
@foos = Foo.all
if query_attributes.any?
@query = Query.new(query_attributes)
if @query.valid?
@foos = Foo.where(created_at: @query.date_range)
else
# do something else
end
end
end
private
def query_attributes
params.fetch(:query)
.permit(:from_date, :to_date)
end
end
并将其与表单和 HTML5 日期助手一起使用:
<%= form_for @query || Query.new do |f| %>
<% if @query.errors.any? %>
<ul>
<% @query.errors.full_messages.each do |m| %>
<li><% m %></li>
<% end %>
</ul>
<% end %>
<div class="row">
<%= f.label :from_date %>
<%= f.date_select :from_date %>
</div>
<div class="row">
<%= f.label :to_date %>
<%= f.date_select :to_date %>
</div>
<%= f.submit %>
<% end %>
它还将逻辑保存在一个单独的域对象中,这很容易测试而不是膨胀控制器。