KatPadi's Point

Ruby Gem That Makes Your Model Activatable

Aktibibo is a simple Ruby gem that makes your model activatable. It allows an ActiveRecord model to be declared as “activatable” thus providing scopes for querying and filtering objects. Of course, the module adds convenience methods for setting an instance as active, inactive or deactivated. As an additional feature, it also saves the activation and deactivation dates because it uses datetime DB columns instead of just simple boolean flags.

Link to gem: https://rubygems.org/gems/aktibibo

So the codes…

Disclaimer: I created this for fun, practice and future convenience when I need an “activatable” module. This is basic.

Anyway, you can check the source code here: https://github.com/katpadi/aktibibo

I just need to explain some parts of the code because my blog is telling me that I am below the minimum recommended 300 words.

module Aktibibo
  module Activatable
    extend ActiveSupport::Concern

    module ClassMethods
      def activatable
        scope :inactive, -> { where(activated_at: nil) }
        scope :active, -> { where.not(activated_at: nil) }
        scope :deactivated, -> { where.not(deactivated_at: nil) }
      end
    end

    def inactive?
      activated_at.blank? && deactivated_at.blank?
    end

    def active?
      activated_at.present? && deactivated_at.blank?
    end

    def deactivated?
      deactivated_at.present?
    end

    def activate
      return if active?
      self.activated_at = Time.now.utc if inactive?
      self.deactivated_at = nil if deactivated?
      save
    end

    def activate!
      fail Errors::AlreadyActivated if active?
      self.activated_at = Time.now.utc if inactive?
      self.deactivated_at = nil if deactivated?
      self.save!
    end

    def deactivate
      return if deactivated?
      self.deactivated_at = Time.now.utc
      save
    end

    def deactivate!
      fail Errors::AlreadyDeactivated if deactivated?
      self.deactivated_at = Time.now.utc
      self.save!
    end
  end
end

First things first… the extend ActiveSupport::Concern means we’re creating a mixin.

The module ClassMethods block basically defines Class methods in itself. For example, in my code above, it adds the declaration of a model to make it “activatable” and it includes the scopes. This function tells the model class that it can query objects by using the defined scopes. Note that you can do a lot of things here other than scopes. But since this is just a simple gem, it’s just doing that.

Going back to the code, everything that is defined within the module and out of the module ClassMethods block will be instance methods. They will be executed within the context of the instance the model that is including the module.

Le setup

  1. Create the necessary columns using a migration:
    rails generate migration add_activated_at_to_foo activated_at:datetime
    rails generate migration add_deactivated_at_to_foo deactivated_at:datetime
  2. Define that your model is “activatable”:
    class Foo < ActiveRecord::Base
      activatable
    end

Usage

Let’s say that an instance foo is available.

Methods

foo.activate
foo.deactivate

Non-bang methods will just return nil (gracefully) if an already active instance is activated. Same goes for deactivate.

Methods with a bang!

foo.activate!
foo.deactivate!

Bang methods, on the other hand, will raise AktibiboError if activated while active or deactivated while deactivated/inactive.

Raising “AktibiboError” is weird. I know.

Boolean methods

foo.active?
foo.deactivated?
foo.inactive?

Scopes

Foo.inactive # Returns all the inactive foos
Foo.activated # Returns all the active foos
Foo.deactivated # Returns all the deactivated foos

Datetimes

foo.activated_at  # Fri, 29 Apr 2016 08:29:03 UTC +00:00
foo.deactivated_at # nil

Link to gem: https://rubygems.org/gems/aktibibo

Leave a Reply

Your email address will not be published. Required fields are marked *