I have a rails form that displays a date in a text_field:
<%= form.text_field :check_in_date %>
The date is rendered as yyyy-m
I spent some time looking in the code, and changing the DATE_FORMAT won't work because Rails never asks for the date format. Felix's solution of setting :value does work, but feels cumbersome: why should I have to set the value of date-specific textfields by hand? So this is a codesmell, and I wanted something better.
Here's my short solution, but then I'll explain it a bit because I'm hoping somebody else will write something better:
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
Somewhat longer explanation:
When a textfield is setting the value attribute, it'll first look in the options hash (which is why Felix's solution works), but if it's not there, it'll call form.object.check_in_date_before_type_cast
, which (after some method_missing magic) will call form.object.attributes_before_type_cast['check_in_date']
, which will look up 'check_in_date' in the @attributes hash inside form.object. My guess is that the @attributes hash is getting the direct MySQL string representation (which follows the 'yyyy-mm-dd' format) before it gets wrapped in a Ruby object, which is why simply setting the DATE_FORMAT doesn't work by itself. So the dynamic method creation above creates methods for all date objects that actually perform the typecast, allowing you to format the date using ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS[:default]
.
This feels a little dirty because the whole purpose of '_before_type_cast' is to avoid a typecast, and this is one of those "thar be dragons" monkeypatches. But still, from what I can tell, it feels like the best of what's around. Maybe somebody else can do a little more digging and find a better solution?
I had similar problems with time attributes/fields. So one can follow this:
http://railscasts.com/episodes/32-time-in-text-field
And it works pretty well.
But I dug into and found another interesting solution. Kind of a ugly monkeypatch, but in some cases it could be more useful that the one from railscasts.
So I have a model with a column named time
(ofc it has a time type). Here is my solution:
after_initialize :init
private
def init
unless time.nil?
@attributes['time'] = I18n.l(time, format: :short)
end
end
As you can see I format the variable which going to be returned by time_before_type_cast
method. So I have properly formatted time in my text input (rendered by FormBuilder
), but if user puts something wrong like 10;23
I still have this and in next request it will be rendered by FormBuilder::text_field
. So user has an opportunity to fix his miserable mistake.