After following Benoitr's suggestions I came up with something similar using virtual attributes. On the View side there are 3 separate select's (year,mon,day) inside of a 'fields_for'. The data is submitted to the controller's mass assignment (no modifications in controller, see asciicasts #16) and then passed to a getter/setter (i.e. virtual attribute) in the model. I'm using Rails 3.0.3, and simpleForm for the view code.
In the View:
<%= f.label "Design Date", :class=>"float_left" %>
<%= f.input :design_month, :label => false, :collection => 1..12 %>
<%= f.input :design_day, :label => false, :collection => 1..31 %>
<%= f.input :design_year, :label => false, :collection => 1900..2020 %>
In the Model:
validate :design_date_validator
def design_year
design_date.year
end
def design_month
design_date.month
end
def design_day
design_date.day
end
def design_year=(year)
if year.to_s.blank?
@design_date_errors = true
else
self.design_date = Date.new(year.to_i,design_date.month,design_date.day)
end
end
def design_month=(month)
if month.to_s.blank?
@design_date_errors = true
else
self.design_date = Date.new(design_date.year,month.to_i,design_date.day)
end
end
def design_day=(day)
if day.to_s.blank?
@design_date_errors = true
else
self.design_date = Date.new(design_date.year,design_date.month,day.to_i)
end
end
#validator
def design_date_validator
if @design_date_errors
errors.add(:base, "Design Date Is invalid")
end
end
'design_date_attr' is the virtual attribute which sets the value of design_date in the database. The getter passes back an hash similar to what gets submitted in the form. The setter checks for blanks and creates a new date object and sets it and also sets the error variable. The custom validator :design_date_validator checks for the error instance variable and sets the errors variable. I used ':base' because the variable name was not human readable and using base removes that value from the error string.
A few things to refactor might be the error checking instance variable, but it seems to work at least. If anyone knows a better way to update the Date objects I'd love to hear it.