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.
No comments yet.
You must be logged in to add your own comment.