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_datescheduled_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 日到“本周五”)

如何将使用日期范围选择器获得的值转换为两个单独的日期和时间?

更改 Rails 4 中的默认日期和时间格式

如何在 Rails 中验证日期?

Pandas 使用单独的时区列转换日期时间

如何将 Json Serializer 配置为在 web api 中为输入和输出参数提供单独的日期转换器?