Introduction

Ruby Gem to store many boolean flags in an integer column by utilizing bits Edit Add topics

CompactFlags comes to serve models with several boolean flags. in large data volumes where the flags can be used to slice the data in several ways. queries tend to be heavier and more indexes are needed by time.

This Gem is made so it can store several flags in one integer attribute through bit wise operations. the attribute represents the state of each record. And is much more performant in database queries

Compatible

Compatible with Rails 4 and 5

Installation

  gem 'compact_flags'

Then run bundle to install the Gem:

  bundle install

Database Migrations

You need to add an integer column only to your model. which will be used later as the flags store, you can just use a migration that adds inter column like below:

  class AddRoles < ActiveRecord::Migration
    def change
      add_column :users, :roles, :integer, :null=>false, :default=>0
    end
  end

Now run migrations:

  bundle exec rake db:migrate

Usage example

After adding the gem and creating an integer column, for example: "roles" to your model, add the "compact_flags" lines passing the flags store column name, and the array of flags

class User < ActiveRecord::Base compact_flags :roles => [:admin, :moderator, :editor] end

  # the corresponding getters and setters for all the boolean flags has been created
  user = User.new
  user.admin = true
  user.admin?            # <=  will return true
  user.moderator?        # <=  will return false
  user.save

Scopes will also be automatically available for objects retrieval from the database. Two names scopes will be available for each flag. with the plural name of the flag, and another one preceded with "not_". scopes gives a suitable flexibility because they can be used in a cascaded style to build complex conditions

  User.admins                               # <=  The pluralize of flag name
  User.not_moderators                       # <=  The pluralize of flag name with 'not_'
  User.not_moderators.admins

Other methods are also available to return the relevant condition part as a string, for concatenation with a condition string. those comes with the in the form of where and where_not, Also available methods to send "OR" in the where clause

  User.admin_value              # => returns associated value to admin => 1
  User.moderator_value          # => returns associated value to moderator => 2
  User.where_admin              # => "(roles & 1) > 0"
  User.where_not_admin          # => "(roles & 1) = 0"
  User.where_not_moderator      # => "(roles & 2) = 0"
  User.roles_or([:admin, :editor])                  # => returns SELECT "users".* FROM "users" WHERE (((roles & 1) > 0) or ((roles & 4) > 0))
  User.roles_or([:admin, :editor], "users.roles")   # => returns SELECT "users".* FROM "users" WHERE (((users.roles & 1) > 0) or ((users.roles & 4) > 0))
  User.roles_values             # => returns ["Admin", "Editor"]

Contributions