Home

Awesome

Save migrations and columns by storing multiple booleans in a single integer.<br/> e.g. true-false-false = 1, false-true-false = 2, true-false-true = 5 (1,2,4,8,..)

class User < ActiveRecord::Base
  include Bitfields
  bitfield :my_bits, 1 => :seller, 2 => :insane, 4 => :sensible
end

user = User.new(seller: true, insane: true)
user.seller # => true
user.sensible? # => false
user.my_bits # => 3

Install

gem install bitfields

Migration

ALWAYS set a default, bitfield queries will not work for NULL

t.integer :my_bits, default: 0, null: false
# OR
add_column :users, :my_bits, :integer, default: 0, null: false

Instance Methods

Global Bitfield Methods

Method NameExample (user = User.new(seller: true, insane: true)Result
bitfield_valuesuser.bitfield_values{"seller" => true, "insane" => true, "sensible" => false}
bitfield_changesuser.bitfield_changes{"seller" => [false, true], "insane" => [false, true]}

Individual Bit Methods

Model Getters / Setters

Method NameExample (user = User.new)Result
#{bit_name}user.sellerfalse
#{bit_name}=user.seller = truetrue
#{bit_name}?user.seller?true

Dirty Methods:

Some, not all, ActiveRecord::AttributeMethods::Dirty and ActiveModel::Dirty methods can be used on each bitfield:

Before Model Persistence
Method NameExample (user = User.new)Result
#{bit_name}_wasuser.seller_wasfalse
#{bit_name}_in_databaseuser.seller_in_databasefalse
#{bit_name}_changeuser.seller_change[false, true]
#{bit_name}_change_to_be_saveduser.seller_change_to_be_saved[false, true]
#{bit_name}_changed?user.seller_changed?true
will_save_change_to_#{bit_name}?user.will_save_change_to_seller?true
#{bit_name}_became_true?user.seller_became_true?true
#{bit_name}_became_false?user.seller_became_false?false
After Model Persistence
Method NameExample (user = User.create(seller: true))Result
#{bit_name}_before_last_saveuser.seller_before_last_savefalse
saved_change_to_#{bit_name}user.saved_change_to_seller[false, true]
saved_change_to_#{bit_name}?user.saved_change_to_seller?true

Examples

Update all users

User.seller.not_sensible.update_all(User.set_bitfield_sql(seller: true, insane: true))

Delete the shop when a user is no longer a seller

before_save :delete_shop, if: -> { |u| u.seller_change == [true, false] }

List fields and their respective values

user = User.new(insane: true)
user.bitfield_values(:my_bits) # => { seller: false, insane: true, sensible: false }

TIPS

Query-mode Benchmark

The query_mode: :in_list is slower for most queries and scales miserably with the number of bits.<br/> Stay with the default query-mode. Only use :in_list if your edge-case shows better performance.

performance

Testing With RSpec

To assert that a specific flag is a bitfield flag and has the active?, active, and active= methods and behavior use the following matcher:

require 'bitfields/rspec'

describe User do
  it { should have_a_bitfield :active }
end

TODO

Authors

Contributors

Michael Grosser<br/> michael@grosser.it<br/> License: MIT<br/> Build Status