write attribute coming from where?

There are datatypes that need to be converted back and forth from a string representation: they need to be parsed both coming from the database, and coming from elsewhere like views.

Dates are an example, and I recently needed to implement a more forgiving converter for decimal numbers. So we have here at least two flows of execution, for example:

   post.date = "22-jan-2007" (from a view)
   post.date = "2007-01-22" (from MySQL)

   invoice.discount = "2,3" (from view)
   invoice.dicount = "2.3" (from MySQL)

A solution to this is to manually parse all dates and decimals in your actions, which is not DRY. I am looking for something more transparent.

A before_filter is a partial solution, it would more or less work, but with the current implementation if you do this

     post.date = "22-jan-2007"
     puts post.date

you get a nil instead of a Date object, because ActiveRecord::Base::Column#type_cast is called by the getter via read_attribute, who does not understand that string.

Another approach is to redefine the setter:

   def date=(v)
     v = my_date_parser(v) if v.is_a?(String)
     write_attribute(:date, v)
   end

but that breaks objet loading from the database because that setter is called by the database adapter as well, and going in that direction my_date_parser receives a String with the format used by the database.

I think having a custom parser for decimals and dates and other locale-sensitive data that comes from views is a common need, but see no way to hook one in the current chains of execution (in a clean way suitable for a framework, I've not written it but surely you can make a hack via Kernel.caller as a quick and dirty solution in a particular application).

Extending the signature of setters in the framework to pass additional information (say, :from => :db) is not an option because it would be used by adapters and thus would break existing code. Do you think is there some point in the framework where this could be addressed? I would be glad to write a patch if that was the case.

-- fxn

Let me add here that as far as DRYness is concerned that approach was considered because the idea was to generate those setters via AR introspection on the columns and their types somewhere, like self.inherited on an abstract model of the application.

-- fxn