September 11, 2007
Modeling tip: Replace booleans with timestamps
Let’s say you’re building a blogging application and you’ve got a Post model. Posts should not show up on the public site until they are approved. Approval is done by clicking an “Approve” button next to the post in the admin area.
Your first inclination (and mine, up until recently) might be to implement this with a boolean column:
1 2 3 4 5 6 7 8 |
class Post < ActiveRecord::Base # assuming posts.approved_at is a boolean column def approve! self.approved = true end end |
That works just fine, and may be all you need. On the other hand, my experience has shown that storing a little bit more data is generally worth the tiny incurred complexity. For example:
1 2 3 4 5 6 7 8 9 10 11 12 |
class Post < ActiveRecord::Base # assuming posts.approved_at is a datetime column def approve! self.approved_at = Time.now end def approved? !approved_at.nil? end end |
This has proven extremely valuable for debugging and audit trail purposes, even if the extra timestamp data is never exposed in a user interface. Approved posts can still be easily queried using SQL by using a WHERE approved_at IS NOT NULL condition.