Rails date format in a text_field

Solution 1:

Simple one time solution is to use :value option within text_field call instead of adding something to ActiveRecord::Base or CoreExtensions.

For example:

<%= f.text_field :some_date, value: @model_instance.some_date.strftime("%d-%m-%Y") %>

Solution 2:

I added these to my initializers/time_formats.rb and it works great:

# Default format for displaying dates and times
Date::DATE_FORMATS[:default] = "%m/%d/%Y"
Time::DATE_FORMATS[:default] = "%m/%d/%Y"

Using Ruby 1.9.3 and Rails 3.2.x

Solution 3:

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?

Solution 4:

Expanding Kamil's answer a bit: add the following method to application_helper.rb:

def date_mdY(date)
  if date.nil?
    ""
  else
    date.strftime("%m-%d-%Y")
  end
end

Then you can modify Kamil's answer slightly:

<%= f.text_field :some_date, :value => date_mdY(@model_instance.some_date) %>

Then you can use this helper method in any other view.

I'm using the jQuery datepicker and the date needed to be in a particular format in order for the default date to be set correctly. Thanks for the answer Kamil!