Rails 4 - 将日期时间转换为单独的日期和时间字段
Posted
技术标签:
【中文标题】Rails 4 - 将日期时间转换为单独的日期和时间字段【英文标题】:Rails 4 - Convert datetime into separate date and time fields 【发布时间】:2013-08-29 23:39:38 【问题描述】:如何将 mysql 日期时间字段转换为两个表单字段 (1) 仅日期,(2) 仅时间,并在表单提交时将两个字段组合回日期时间格式?
这将允许使用以下 gem,但将日期存储在单个日期时间字段中:
gem 'bootstrap-datepicker-rails'
gem 'bootstrap-timepicker-rails'
提前致谢!
【问题讨论】:
【参考方案1】:在@Althaf 的帮助下找到了解决方案
为 model.rb 添加了虚拟属性
使用before_save
回调转换回日期时间。
before_save :convert_to_datetime
def sched_date_field
sched_date.strftime("%d/%m/%Y") if sched_date.present?
end
def sched_time_field
sched_time.strftime("%I:%M%p") if sched_time.present?
end
def sched_date_field=(date)
# Change back to datetime friendly format
@sched_date_field = Date.parse(date).strftime("%Y-%m-%d")
end
def sched_time_field=(time)
# Change back to datetime friendly format
@sched_time_field = Time.parse(time).strftime("%H:%M:%S")
end
def convert_to_datetime
self.sched_time = DateTime.parse("#@sched_date_field #@sched_time_field")
end
使用 Rails 4,需要将 sched_date_field 和 sched_time_field 添加到 controller.rb
中的强参数中以下是 _form.html.erb
中的字段<%= f.label :sched_date_field, "Scheduled Date" %>
<%= f.text_field :sched_date_field, :class => "datepicker" %>
<%= f.label :sched_time_field, "Scheduled Time" %>
<%= f.text_field :sched_time_field, :class => "timepicker" %>
【讨论】:
严格参数是指“强参数”吗?此外,这段代码似乎在 sched_time 上引发了一个未定义的变量错误。 这有点极端,但如果您使用这种技术并要求对sched_time
字段进行任何验证,它将失败。您可以尝试将before_save
更改为before_validation
。但同样,如果您有级联验证,这可能会失败。在这个简短的评论中有点难以解释,但相信我,它会失败。
@Karl 你推荐什么?我遇到了这个问题。我正在考虑更改我的数据模型以将日期、时间和时区存储为 3 个单独的字段。
@Turgs 好吧,已经有一段时间了,但我想我通过在 datepicker 和 timepicker 上使用 javascript 回调将它组合回单个 datetime 并提交它来解决它。
对于那些使用 rails 5 的人 - 好消息是 rails 5 使用虚拟属性为您完成所有类型转换,只需使用属性 API:api.rubyonrails.org/classes/ActiveRecord/Attributes/…【参考方案2】:
你可以使用date_time_attribute gem:
class MyModel < ActiveRecord::Base
include DateTimeAttribute
date_time_attribute :scheduled_at
end
它将允许您分别设置schedule_at_date
和scheduled_at_time
。设置属性后,值将组合成schedule_at
。
【讨论】:
【参考方案3】:你可以使用虚拟属性See this Railscast,如果你有专业订阅the revised one。
基本上在视图中你会如下
<%= f.label :date_field %>
<%= f.text :date_field %>
<%= f.label :time_field %>
<%= f.text :time_field %>
您的数据库仍会保留一个字段,我将称之为 full_date
现在在您的模型中,您必须按如下方式定义上述 2 个字段。
def date_field # What this returns will be what is shown in the field
full_date.strftime("%m-%d'%y") if full_date.present?
end
def time_field
full_date.strftime("%I:%M%p") if full_date.present?
end
def time_field=(time)
full_date = DateTime.parse("#date_field #time_field)
end
由于您使用的是 Rails 4,因此您必须在强参数中允许 date_field 和 time_field。
【讨论】:
我认为这就是这样做的方法。我必须在您的解决方案中添加一些内容才能使其正常工作。 您能否提及您所做的更改,以便我可以根据您所做的编辑我的答案,以便其他人以后可以参考 无法确定如何在此回复评论区正确格式化解决方案,因此我在下面发布了解决方案。感谢您的帮助。 太棒了。继续并接受您自己的答案以将此问题设置为已解决。【参考方案4】:另外,我在控制器中设置了一个解决方案,该解决方案在创建对象之前执行所有日期时间转换,因为更改模型中的数据会影响我的所有测试和验证。 “事件”是我在此处创建的对象,并为其分配了日期时间值。
#In the controller:
def convert_to_datetime_and_assign(event, params)
date_field = Date.parse(params[:date_field]).strftime("%Y-%m-%d")
start_time_field = Time.parse(params[:start_time_field]).strftime("%H:%M:%S")
end_time_field = Time.parse(params[:end_time_field]).strftime("%H:%M:%S")
event.start_time = DateTime.parse("#date_field #start_time_field")
event.end_time = DateTime.parse("#date_field #end_time_field")
event
rescue ArgumentError
event.errors.add(:start_time, :invalid, message: "Date or time was invalid")
event
end
在创建和更新控制器方法中我调用了上面的方法:
@event = convert_to_datetime_and_assign(@event, event_params)
我在表单中添加了 date_field、start_time_field 和 end_time_field 字段,用于创建/更新“事件”。在模型中,我添加了一个访问器来访问这些值。
attr_accessor :date_field, :start_time_field, :end_time_field
【讨论】:
以上是关于Rails 4 - 将日期时间转换为单独的日期和时间字段的主要内容,如果未能解决你的问题,请参考以下文章
Ruby/Rails:将日期时间转换为自然语言(例如 2012 年 3 月 23 日到“本周五”)