Demystifiying Rails Model attributes overriding

28 Jul
2009

In the java world, you have setter and getter in your model which are called ALWAYS. Change some behaviour in the setter/getter and you are done. Things are somewhat more complicated if we look at rails and activerecord.

Imagine you have a model that should parse both minutes and a formatted hour/minute string as data:

testcase.estimated_time = "90"
testcase.estimated_time = "01:30"

As the data is saved as integer in minutes, some conversion has to be done to parse the second string. To get this right, it should be done in the model itself (as we may have various places in our web app where it can be edited)

My first try was to simply override the setter and getter in the model:

# THIS DOES NOT WORK!

def estimated_time
  self['estimated_time']
end

def estimated_time=(_estimated_time)
  self['estimated_time'] = _estimated_time
end

Well, u can assume that this doesn’t work. Why? The setter is not always called in rails – only if you directly adress estimated time, but NOT if you update a bunch of attributes (which is the normal way on a post update)

Solution

ActiveRecord defines the estimated_time= method on the testcase class itself.
There is a technique called “methode chaining”, but this only works for associations.

The best way to go is by using a virtual property.

  def estimated_time_string
    helper.format_time self.estimated_time, ""
  end

  def estimated_time_string=(_estimated_time)
    self.estimated_time = convert_time(_estimated_time)
  end

Change your forms to use estimated_time_string instead of estimated_time.

Related posts:

  1. Rails has_many and dynamic conditions

1 Response to Demystifiying Rails Model attributes overriding

Avatar

Martin Schuerrer

July 28th, 2009 at 5:48 pm

Hm, it works for me :) (To be more precise, the setter is called both with update_attributes and new)

Take a look at the code at http://github.com/MSch/petertest/tree/master (app/models/peter.rb and test/unit/peter_test.rb)

What exactly about mass assignment isn’t working for you?

Irregardless I think moving the time parsing code from the controller into the model might by DRY but is nevertheless a bad design decision. I’d take a look at the presenter pattern (http://www.caboo.se/articles/2007/8/23/simple-presenters and http://github.com/giraffesoft/active_presenter/tree/master) This would seem a lot cleaner to me.

Comment Form

top

Switch to our mobile site