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

问题描述 投票:0回答:6

问题

  1. 我有一个带有日期属性的 Ruby on Rails 模型。
  2. 在此模型的表单中,我使用带有 JQuery 日期选择器的单个文本字段来表示此属性(而不是像 Rails 自定义那样分别对应年、月和日的下拉列表)。
  3. 日期选择器以
    mm/dd/yyyy
    格式插入日期。
  4. Rails 需要采用
    dd/mm/yyyy
    格式的日期。

示例

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

问题

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

备注:

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

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

ruby-on-rails-3
6个回答
16
投票

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

从Ruby 1.9开始,日期解析的标准格式是

dd/mm/yyyy
,以便更好地适应国际用户。更多详细信息可以在这个SO答案中找到。

该标准在 Rails 中得到维护,因为

Date.parse
现在用于处理来自表单输入的数据。使用
before_validation
回调不起作用,因为该字段将被回调方法接收为
nil

现在有两个 gem 处理这个特定问题,即 Rails 中的日期解析不遵循

I18n.locale
中的区域设置。两者似乎都运作良好。

  1. delocalize,作者:clemens - 似乎已在相当多的项目中成功应用,并且目前拥有最多的星星。

  2. i18n_alchemy by carlosantoniodasilva - 这个最近发布了。作者是 Rails 核心团队成员,并且是一名非常活跃的成员。绝对值得一看。


3
投票

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

例如,假设您照常使用表单生成器,为模型的日期属性添加隐藏字段:

f.hidden_field :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
字段值初始化它(如果它是编辑表单)。



0
投票
你可以尝试做这样的事情。

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

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
    

0
投票
Rails 5

为我们提供了属性API,它允许我们使用自定义行为定义模型属性类型。在本例中,我们需要一个常规的旧 :date

,但在转换应用程序值以在数据库查询中使用时进行特殊处理。

我们可以像这样定义新属性:

# in lib/types/mdy_date.rb class MDYDate < ActiveRecord::Type::Date MDY_FORMAT = /(\d{2})\/(\d{2})\/(\d{4})/ MDY_SWAP = '\\2/\\1/\\3' def cast(value) if value.is_a?(::String) && value.match?(MDY_FORMAT) # swap day and month so Ruby's Date._parse reads it correctly super(value.gsub(MDY_FORMAT, MDY_SWAP)) else super end end end # in config/initializers/types.rb ActiveRecord::Type.register(:mdy_date, MDYDate) # in models/your_model.rb attribute :date_field, :mdy_date # This will now return records where date_field # is 2024-06-07 (June 7), rather than 2024-07-06 (July 6), # but otherwise behaves like and is serialized to Date YourModel.where(date_field: '06/07/2024')
    
© www.soinside.com 2019 - 2024. All rights reserved.