我有一个在text_field中显示日期的rails表单:
<%= form.text_field :check_in_date %>
日期呈现为yyyy-mm-dd
我正在试图弄清楚如何将其显示为mm-dd-yyyy
我尝试添加此配置,但它无效。
ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(
:default => '%m/%d/%Y'
)
答案 0 :(得分:63)
简单的一次性解决方案是在:value
调用中使用text_field
选项,而不是向ActiveRecord::Base
或CoreExtensions
添加内容。
例如:
<%= f.text_field :some_date, value: @model_instance.some_date.strftime("%d-%m-%Y") %>
答案 1 :(得分:37)
我将这些添加到我的initializers/time_formats.rb
,效果很好:
# Default format for displaying dates and times
Date::DATE_FORMATS[:default] = "%m/%d/%Y"
Time::DATE_FORMATS[:default] = "%m/%d/%Y"
使用Ruby 1.9.3和Rails 3.2.x
答案 2 :(得分:11)
我花了一些时间查看代码,并且更改DATE_FORMAT将不起作用,因为Rails从不要求日期格式。 Felix的设置解决方案:值确实有效,但感觉很麻烦:为什么我必须手动设置特定于日期的文本字段的值?所以这是一个代码,我想要更好的东西。
这是我的简短解决方案,但后来我会解释一下,因为我希望其他人会写出更好的东西:
MyModel < ActiveRecord::Base
# ...
self.columns.each do |column|
if column.type == :date
define_method "#{column.name}_before_type_cast" do
self.send(column.name).to_s
end
end
end
end
更长的解释:
当文本字段设置值属性时,它将首先查看选项哈希(这就是为什么菲利克斯的解决方案有效),但如果它不在那里,它将调用form.object.check_in_date_before_type_cast
,这(在一些method_missing魔法之后)将调用form.object.attributes_before_type_cast['check_in_date']
,它将在form.object内的@attributes哈希中查找“check_in_date”。我的 guess 是@attributes哈希在获取Ruby对象之前获得直接MySQL字符串表示(遵循'yyyy-mm-dd'格式),这就是为什么简单地设置DATE_FORMAT本身不起作用。因此,上面的动态方法创建为实际执行类型转换的所有日期对象创建方法,允许您使用ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS[:default]
格式化日期。
这感觉有点脏,因为'_before_type_cast'的整个目的是为了避免类型转换,这就是那些“可能是龙”的monkeypatches之一。但是,从我所知道的情况来看,感觉就像周围最好的一样。也许其他人可以多做一些挖掘并找到更好的解决方案?
答案 3 :(得分:9)
稍微扩展Kamil的答案:将以下方法添加到application_helper.rb:
def date_mdY(date)
if date.nil?
""
else
date.strftime("%m-%d-%Y")
end
end
然后你可以稍微修改一下卡米尔的答案:
<%= f.text_field :some_date, :value => date_mdY(@model_instance.some_date) %>
然后您可以在任何其他视图中使用此辅助方法。
我正在使用jQuery日期选择器和特定格式所需的日期,以便正确设置默认日期。谢谢你的回答Kamil!
答案 4 :(得分:7)
ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS[:default] = '%m/%d/%Y'
<%= form.text_field :check_in_date, value: model.check_in_date.to_s %>
答案 5 :(得分:5)
这个使用位置,格式为:
<%= f.text_field :date3, value: ( l @model.date3 if @model.date3? ) %>
在en.yml(或es.yml)的位置
en:
date:
formats:
default: "%d/%m/%Y"
答案 6 :(得分:2)
使这项工作分为两部分,第三部分使这一切能够顺利进行。如果您只想复制粘贴,请继续并滚动到最后。
Date
根据需要格式化自己有一堆core extensions to Date in ActiveSupport,但没有一个创建新的日期类。如果您正在使用Date
,这是Rails在您的数据库中有date
列时返回的内容,则将该日期转换为字符串的方法为Date#to_formatted_s
。 ActiveSupport
扩展名会添加此方法,并且会将to_s
方法替换为它,因此当您调用Date#to_s
(可能是隐式)时,您会获得Date.to_formatted_s
。
有两种方法可以更改to_formatted_s
使用的格式:
Date::DATE_FORMATS
中的格式。)更改:default
映射到的格式。由于to_formatted_s
设置了默认值:default
,因此当您在不传递参数的情况下调用Date#to_s
时,您将获得Date::DATE_FORMATS[:default]
指定的格式。您可以在应用程序范围内覆盖默认值,如下所示:
Date::DATE_FORMATS[:default] = "%m/%d/%Y"
我在config/initializers/date_formats.rb
这样的初始化程序中设置了此集。它很粗糙,不支持使用本地化进行更改,但是Date#to_s
可以返回所需的格式,而无需修补任何猴子或将日期显式转换为字符串并传入参数。
默认情况下,您的ActiveRecord
实例cast date columns使用好的'ISO 8601,如下所示:yyyy-mm-dd
。
如果它与那种格式不完全匹配(例如,它是斜线分隔的),它会回退到使用Ruby的Date._parse,这稍微宽松一点,但仍然希望看到几天,几年甚至几年:dd/mm/yyyy
。
要让Rails以您收集它们的格式解析日期,您只需将cast_value
方法替换为您自己的方法即可。您可以 monkeypatch ActiveRecord::Types::Date
,但滚动自己继承的类型并不困难。
我喜欢使用Chronic来解析用户输入的日期字符串,因为它会提供更多的狗屎,例如“明天”,或“1月1日99”,甚至像“5 / 6-99”这样的疯狂输入(1999年5月6日)。由于Chronic返回Time
的实例,并且我们覆盖了提供的cast_value
方法,因此我们需要在其上调用to_date
。
class EasyDate < ActiveRecord::Type::Date
def cast_value(value)
default = super
parsed = Chronic.parse(value)&.to_date if value.is_a?(String)
parsed || default
end
end
现在我们只需告诉ActiveRecord使用EasyDate
代替ActiveRecord::Type::Date
:
class Pony < ApplicationRecord
attribute :birth_date, EasyDate.new
end
这很有效,但是如果你像我一样,你现在想要做更多的工作,这样你将来可以节省3秒。如果我们告诉ActiveRecord总是将EasyDate用于仅仅是日期的列,该怎么办?我们可以。
ActiveRecord为您提供有关模型的各种信息,用于处理幕后的所有“魔法”。它为您提供了attribute_types
的一种方法。如果你在你的控制台中运行它,你就会呕吐 - 这有点可怕,你只需要“哦,永远不要”。如果你像某种怪物一样深入研究这种呕吐物,它只是一个看起来像这样的哈希:
{ column_name: instance_of_a_type_object, ... }
不是可怕的东西,但由于我们开始捅内部,这些instance_of_a_type_object
的检查输出最终会变得迟钝和“封闭”。像这样:
#<ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Money:0x007ff974d62688
谢天谢地,我们真的只关心一个:ActiveRecord::Types::Date
,所以我们可以缩小范围:
date_attributes = attribute_types.select { |_, type| ActiveRecord::Type::Date === type }
这为我们提供了一个列表,列出了我们想要使用上升周期的EasyDate
。现在我们只需告诉ActiveRecord在上面那些属性上使用EasyDate:
date_attributes.each do |attr_name, _type|
attribute attr_name, EasyDate.new
end
基本上就是这样,但我们需要将它们粘合在一起。如果你正在使用ApplicationRecord
,你可以将其放入其中并进入比赛:
def inherited(klass)
super
klass.attribute_types.select { |_, type| ActiveRecord::Type::Date === type }.each do |name, _type|
klass.attribute name, EasyDate.new
end
end
如果您不想“污染”ApplicationRecord
,您可以像我一样做,创建一个模块并使用它扩展ApplicationRecord
。如果您使用ApplicationRecord
,则需要创建模块并扩展ActiveRecord::Base
。
module FixDateFormatting
# the above `inherited` method here
end
# Either this...
class ApplicationRecord < ActiveRecord::Base
extend FixDateFormatting
end
# ...or this:
ActiveRecord::Base.extend(FixDateFormatting)
如果您不关心如何并且只想让它发挥作用,您可以:
gem "chronic"
添加到您的Gemfile和bundle install
ApplicationRecord
config/initializers/date_formatting.rb
以下是要复制的代码:
Date::DATE_FORMATS[:default] = "%m/%d/%Y"
module FixDateFormatting
class EasyDate < ActiveRecord::Type::Date
def cast_value(value)
default = super
parsed = Chronic.parse(value)&.to_date if value.is_a?(String)
parsed || default
end
end
def inherited(subclass)
super
date_attributes = subclass.attribute_types.select { |_, type| ActiveRecord::Type::Date === type }
date_attributes.each do |name, _type|
subclass.attribute name, EasyDate.new
end
end
end
Rails.application.config.to_prepare do
ApplicationRecord.extend(FixDateFormatting)
end
答案 7 :(得分:1)
转到environment.rb文件并添加以下内容:
ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(
:default => '%m-%d-%Y' )
如果您想阅读更多内容,请查看official文档。
答案 8 :(得分:1)
所以我在模型中做了类似的事情。
def start_date
super.strftime "%Y/%m/%d %H:%M"
end
假设您在模型中有一个名为start_date
的列,并希望在表单中显示另一种格式,只需在模型中覆盖其值。
表格中不需要改变任何内容。
<%= f.text_field :start_date, class: 'form-control' %>
答案 9 :(得分:1)
我首选的方法是使用虚拟属性。有一个短RailsCast on the subject(3米),但结果是虚拟属性允许您在表单中显示模型属性时使用非标准格式,反之亦然(即将表单数据保存到模型中。
基本上,您可以在模型上定义“虚拟属性”,而不是为check_in_date
属性创建表单字段:
class Reservation
def check_in_date_string
check_in_date.strftime('%m-%d-%Y')
end
def check_in_date_string=(date_string)
self.check_in_date = Date.strptime(date_string, '%m-%d-%Y')
end
end
现在,您可以创建与check_in_date_string
而不是check_in_date
对应的表单字段:
<%= f.text_field :check_in_date_string %>
就是这样!无需明确指定value
选项,并且在提交此表单时,模型将得到适当更新。
答案 10 :(得分:0)
如果您可以手动设置值,则可以使用 created_at.strftime(“%m-%d-%Y”) http://snippets.dzone.com/tag/strftime。
答案 11 :(得分:0)
我遇到了与时间属性/字段类似的问题。所以可以遵循这个:
http://railscasts.com/episodes/32-time-in-text-field
它运作良好。
但是我挖了进来,找到了另一个有趣的解决方案。有点丑陋的monkeypatch,但在某些情况下,它可能比来自railscast的那个更有用。
所以我有一个名为time
的列的模型(ofc它有一个时间类型)。这是我的解决方案:
after_initialize :init
private
def init
unless time.nil?
@attributes['time'] = I18n.l(time, format: :short)
end
end
如您所见,我格式化了time_before_type_cast
方法返回的变量。所以我在文本输入中正确格式化了时间(由FormBuilder
呈现),但如果用户输错了10;23
,我仍然有这个,在下一个请求中它将由FormBuilder::text_field
呈现。所以用户有机会解决他那个可怜的错误。
答案 12 :(得分:0)
对于有兴趣在特定位置而不是在整个项目中进行格式化的人员,建议使用几个答案来检查是否为空,我想使用 try 和 strftime 来添加该值将有助于缩短时间。
<%= f.fields_for :assets_depreciations do |asset| %>
<tr>
<td>
<%= asset.text_field :depreciation_date, value: asset.object.depreciation_date.try(:strftime, "%d-%m-%Y") %>
</td>
</tr>
<% end %>
答案 13 :(得分:0)
汤姆·罗西斯(Tom Rossis)答案的一个小改进是使用I18n.localize
方法,因此默认设置始终是在当前用户的语言环境中:
initializers/date_time_i18n_formatter.rb
Date::DATE_FORMATS[:default] = ->(date) { I18n.localize date, format: :default }
Time::DATE_FORMATS[:default] = ->(time) { I18n.localize time, format: :default }