RailsConf Recap: Named Callbacks
Another topic we touched briefly on at RailsConf was the idea of named callbacks.
Consider this snippet (also from Brian Cooke’s expense tracking application):
1 2 3 4 5 6 7 8 |
class Expense < ActiveRecord::Base protected def before_create if self.created_at == Time.now.to_date.to_time self.created_at = Time.now end end end |
One thing to keep in mind here is that when a new Expense record is created, the created_at column is used to track when the expense originally occurred, not when the record was created. As a special case, if the timestamp is 00:00 of the current day, then it is assumed to actually be the current time.
Now, looking at that code, it’s definitely not immediately obvious what it is trying to do. In fact, it took me a few minutes of steady concentration (and cross-referencing other parts of the project) to understand it. The fact that it uses a generic “before_create” callback makes it hard to know the purpose of the method, and the use of “Time.now.to_date.to_time” (though effective) is pretty intention-obscuring.
Here’s a clearer, more self-documenting approach, using a named callback:
1 2 3 4 5 6 7 8 9 10 |
class Expense < ActiveRecord::Base before_create :make_created_now_if_created_today protected def make_created_now_if_created_today if self.created_at == Time.now.beginning_of_day self.created_at = Time.now end end end |
The named callback helps make it clearer what the purpose of the method is (though in this case, an additional comment would not be amiss). Also, ActiveSupport comes to the rescue, allowing us to convert the convoluted “Time.now.to_date.to_time” into the more self-documenting “Time.now.beginning_of_day”. (Alternatively, you might prefer “Time.now.midnight”, though I find “beginning_of_day” to be clearer, since it reveals the intention better.)
Always look for ways to make your code document itself. Ruby is one of the most readable programming languages I’ve ever used, and it’s a pity to not take advantage of that readability as often as you can.

