在从表单中的文本字段解析日期时,如何更改ActiveRecord期望的格式?

时间:2013-03-20 18:25:18

标签: ruby-on-rails-3

问题

  1. 我有一个带有Date属性的Ruby on Rails模型。
  2. 在此模型的表单中,我使用带有JQuery日期选择器的单个文本字段来表示此属性(不是每年,每月和每天的下拉列表,而是Rails自定义)。
  3. 日期选择器以mm/dd/yyyy格式插入日期。
  4. Rails期望日期为dd/mm/yyyy格式。
  5. 实施例

    • 如果用户选择 2012年3月12日,则日期选择器将03/12/2012放入,由Rails解释为 2012年12月3日
    • 如果用户选择 2012年3月20日,则日期选择器会将03/20/2012放入由Rails解释为2012年 20个月的第3天由于这个日期不存在,Rails会将其转换为nil值(我认为)。

    问题

    如何更改Rails在解析此日期文本字段时使用的日期格式?

    注意:

    1)我不想更改datepicker插入文本字段的日期格式,

    2)我不是要求在视图中显示我的日期属性。

5 个答案:

答案 0 :(得分:14)

我最初认为这可以通过Rails国际化功能解决,但事实证明我错了。

自Ruby 1.9以来,日期解析的标准格式为dd/mm/yyyy,以便更好地适应国际用户。有关详细信息,请参阅this SO answer

该标准在Rails中维护,因为Date.parse现在用于处理来自表单输入的数据。使用before_validation回调将无效,因为该字段将通过回调方法接收为nil

现在有两个宝石处理这个特定问题,即Rails中的日期解析不遵循I18n.locale的区域设置。两者似乎都运作良好。

    克莱门斯的
  1. delocalize - 似乎已成功应用于一个不错的数字或项目中,目前拥有最多的星星。

  2. carlosantoniodasilva的
  3. i18n_alchemy - 这个已经被释放了。作者是Rails核心团队成员,并且非常活跃。绝对值得一看。

答案 1 :(得分:3)

由于您不想更改选择器的格式,我建议您使用隐藏字段作为实际的模型属性。

例如,假设您像往常一样使用表单构建器,为模型的日期属性添加隐藏字段:

f.hidden_field :date

然后,对于选择器文本输入,不要将其绑定到模型的date属性。假设隐藏字段的ID为'modelname_date',而选择器文本输入的ID为'date_picker',请使用以下命令使其工作:

$(function(){
  $("#date_picker").datepicker({altField: '#nodelname_date', altFormat: 'dd/mm/yyyy'});
});

通过这种方式,日期选择器将日期显示为“mm / dd / yyyy”,但Rails会将日期显示为“dd / mm / yyyy”。

<强>更新

如果你想在Rails方面解决这个问题,这是我建议的另一个解决方案:

  • 向模型添加虚拟财产:attr_accessor :bad_format_date
  • 添加before_validation回调,在其中解析输入日期并将其分配到真实字段:
before_validation do
  self.date = Date.strptime(bad_format_date, "%m/%d/%Y")
end

然后,对于视图中的表单,请使用bad_format_date,但使用date字段值初始化它(如果它是编辑表单)。

答案 2 :(得分:0)

timeliness gem使ruby日期/时间解析更加可定制,并与Rails很好地集成。

由于您正在使用Rails,请务必同时查看validates_timeliness项目。它包括ActiveModel的所有及时性和复杂的日期/时间验证方法。

答案 3 :(得分:0)

您可以尝试做这样的事情。

$(function(){
 $('#date_picker').datepicker( {
      beforeShowDay: $.datepicker.noWeekends, 
      showOtherMonths: true,
      selectOtherMonths: true,
      dateFormat: 'dd-mm-yy',
      defaultDate: date,
      gotoCurrent: true

}); 

答案 4 :(得分:0)

我只需将以下猴子补丁添加到config / time_formats.rb

class Date
  class << self
    alias :euro_parse :_parse
    def _parse(str,comp=false)
      str = str.to_s.strip
      if str == ''
        {}
      elsif str =~ /^(\d{1,2})[-\/](\d{1,2})[-\/](\d{2,4})/
        year,month,day = $3.to_i,$1,$2
        date,*rest = str.split(' ')
        year += (year < 35 ? 2000 : 1900) if year < 100
        euro_parse("#{year}-#{month}-#{day} #{rest.join(' ')}",comp)
      else
        euro_parse(str,comp)
      end  
    end
  end
end