Time for A Boolean
Sally: Hey, we need to add a flag to Post
Jean: What for?
Sally: Well, we want to let users "delete" posts, but not actually lose the data.
Jean: Sounds reasonable. But what about later, when we have to know when a post was deleted?
Sally: That's a good point, but if we add a timestamp now we have to write all sorts of methods to keep a nice interface on Post...
Jean: Time for A Boolean!
Wait, what?
rails generate migration AddDeletedAtToPosts deleted_at:timestamp
class Post < ActiveRecord::Base
time_for_a_boolean :deleted
...
end
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
if @post.deleted?
raise ActiveRecord::RecordNotFound
end
end
def destroy
post = Post.find(params[:id])
post.deleted = true
post.save
redirect_to posts_url
end
end
You keep on saying things and I don't get it.
Okay, let's take a look at what happens.
When we call time_for_a_boolean :deleted
in the Post class definition, several
methods are defined:
Method | Description |
---|---|
Post#deleted |
true if Post#deleted_at is set to a time before Time.current , false otherwise |
Post#deleted? |
Alias for Post#deleted
|
Post#deleted= |
Sets the timestamp to Time.current if the new value is true, and nil otherwise |
These methods allow you to use a timestamp as you would a boolean value in your application.
Okay... why?
- Audit for when a flag was set. Future you wants this.
-
COUNT(posts.deleted_at)
gives you the count of deleted posts, which is useful when writing a report. Define and usePost.deleted.count
when you have Ruby available.
Other Options
If you have a date or time column that does not follow the attribute_at
convention,
you can specify the attribute name:
class User < ActiveRecord::Base
time_for_a_boolean :expires, :expires_on
end
This is especially useful when using date only columns.