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 deactivated_at:datetime
  2. Define that your model is “activatable” by adding the ff in your model:
    class Foo < ActiveRecord::Base
      activatable
    end
    Foo model

    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 *