Low commit activity in last 3 years
A long-lived project that still receives updates
Use timestamp values to represent boolean data such as deleted, published, or subscribed.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

Time for A Boolean

Build Status Code Climate Coverage Status

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 use Post.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.