When using Rails date_select with :prompt => true I see some very strange behavior when submitting the form without all fields selected. Eg.
Submitting the form with January selected but the day and year fields left at the default prompt results in January 1st 0001 getting passed to the model validation. If validation fails and the form is rendered again January is still selected (correctly) but the day is set to 1 (incorrectly). If the form is submitted with just the year selected, both month and day get set to 1.
This is very strange behavior – can anyone give me a workaround?
The problem has to do with multiparameter assignment. Basically you want to store three values into one attribute (ie.
written_at). The date_select sends this as{ 'written_at(1)' => '2009', 'written_at(2)' => '5', 'written_at(3)' => '27' }to the controller. Active record packs these three values into a string and initializes a new Date object with it.The problem starts with the fact that Date raises an exception when you try to instantiate it with an invalid date,
Date.new(2009, 0, 1)for instance. Rails catches that error and instantiates a Time object instead. The Time class with timezone support in Rails has all kinds of magic to make it not raise with invalid data. This makes your day turn to 1.During this process active record looses the original value hash because it packed the
written_atstuff into an array and tried to create a Date or Time object out of it. This is why the form can’t access it anymore using thewritten_at_before_time_castmethod.The workaround would be to add six methods to your model:
written_at_year,written_at_year=, andwritten_at_year_before_type_cast(for year, month and day). Abefore_validationfilter can reconstruct the date and write it to written_at.