将多个字段Rails转换为一个模型属性

我一直在寻找,但似乎无法找到一个很好的解决方案。

我的表单有一个日期(带有datepicker的文本字段)和一个时间(带有timepicker的文本字段),我想将其映射到名为due_at的模型字段。

到目前为止,我一直在我的控制器中处理它,使用单独的参数将其连接到日期时间,然后手动设置模型字段,但它很混乱,并且认为这个逻辑应该保存在模型/视图中。

我希望能够将两个表单字段处理为模型中的属性,然后将其拆分出来以获取错误,编辑操作等。基本上是一种自定义方式来执行标准datetime_select所做的事情,但我自己触摸它。

有什么东西可以放在我的模型中吗?

 def due_at=(date, time) ... end 

我一直在寻找一些地方,但无法知道你将如何做到这一点。 人们说使用javascript填充一个隐藏的字段,但对于一个非常简单的问题,似乎不是最干净的解决方案。

任何建议/帮助将不胜感激。

谢谢。

第一:请重命名您的字段,因为created_at可能会导致与ActiveRecord冲突。

我为格式为M / D / YYYY H:M(小时/分钟,24小时格式)的字段做了这个

在你的模型中:

 attr_accessor :due_date, :due_time before_validation :make_due_at def make_due_at if @due_date.present? && @due_time.present? self.due_at = DateTime.new(@due_date.year, @due_date.month, @due_date.day, @due_time.hour, @due_time.min) end end def due_date return @due_date if @due_date.present? return @due_at if @due_at.present? return Date.today end def due_time return @due_time if @due_time.present? return @due_at if @due_at.present? return Time.now end def due_date=(new_date) @due_date = self.string_to_datetime(new_date, I18n.t('date.formats.default')) end def due_time=(new_time) @due_time = self.string_to_datetime(new_time, I18n.t('time.formats.time')) end protected def string_to_datetime(value, format) return value unless value.is_a?(String) begin DateTime.strptime(value, format) rescue ArgumentError nil end end 

现在在视图中:

 <%= text_field_tag :due_time, I18n.l(@mymodel.due_time, :format => :time) %> <%= text_field_tag :due_date, I18n.l(@mymodel.due_date, :format => :default) %> 

现在在config / locales / en.yml(如果是英文)

  date: formats: default: "%m/%d/%Y" time: formats: time: "%H:%M" 

您可以更改当然的日期格式。

我认为date_time_attribute gem是一个不错的选择:

 class Task < ActiveRecord::Base include DateTimeAttribute date_time_attribute :due_at end 

它允许您分别设置due_at_datedue_at_time

 form_for @event do |f| f.text_field :due_at_date f.text_field :due_at_time f.submit end # this will work too: form_for @event do |f| f.date_select :due_at_date f.time_select :due_at_time, :ignore_date => true f.text_field :due_at_time_zone f.submit end # or form_for @event do |f| f.date_select :due_at_date f.text_field :due_at_time f.submit end 

这是一个例子:

 task = Task.new task.due_at # => nil # Date set task.due_at_date = '2001-02-03' task.due_at_date # => 2001-02-03 00:00:00 +0700 task.due_at_time # => 2001-02-03 00:00:00 +0700 task.due_at # => 2001-02-03 00:00:00 +0700 # Time set task.due_at_time = '10:00pm' task.due_at_time # => 2013-12-02 22:00:00 +0800 task.due_at_date # => 2001-02-03 00:00:00 +0700 task.due_at # => 2001-02-03 22:00:00 +0700 # Time zone is applied as set task.due_at_time_zone = 'Moscow' task.due_at # => Mon, 03 Feb 2013 22:00:00 MSK +04:00 task.due_at_time_zone = 'London' task.due_at # => Mon, 03 Feb 2013 22:00:00 GMT +00:00 

它还允许您玩时区,使用慢性等。