Merging the boolean attributes into one single bitmasked integer attribute is a solution. Then the integer value represents multiple flags (booleans) bitwise. Metaphorical spoken: several boolean attributes are stacked into the value of one integer attribute
The advantages for bitmasking boolean attributes are:
- much lower attribute baggage: 1 integer (usually 4 bytes) can take up to 32 boolean attributes
- flexible database structure (a new boolean attribute does not require a database migration)
- readable semantic values (the values are meaningful compared to the boolean true/ false)
- dynamic access to the bitmask values, which feels more Rubyish
- reduces readability in the database layer (the stacked integer value is hiding the meaningful attribute names)
- introduces a (very small) Ruby layer for processing the stacked values (back and forth)
- means to work around attribute representations, which rely on the database data type (like simple_form gem)
create_table :people do |t| t.string :name t.boolean :product_owner, null: false, default: false t.boolean :developer, null: false, default: false t.boolean :scrum_master, null: false, default: false t.boolean :sales, null: false, default: false endthe same model can be refactored to:
create_table :people do |t| t.string :name t.integer :roles endThe appropriate model:
class Person < ActiveRecord::Base bitmask :roles, as: [:scrum_master, :product_owner, :developer, :sales] endand by now the bitmask can be used:
Person.values_for_roles => [:scrum_master, :product_owner, :developer, :sales] person = Person.create name: 'Bob', roles: [:scrum_master, :developer] person.roles => [:scrum_master, :developer] person.roles << :sales person.roles => [:scrum_master, :developer, :sales] person.roles? :developer => trueIf the bitmask has to be represented by check boxes in the Ruby on Rails view:
<% Person.values_for_roles.each do |role| %> <%= check_box_tag 'person[roles][]', role, @person.roles.include?(role), id: role %> <%= label_tag role, role.to_s.humanize %> <% end %>generates the HTML:
Using bitmask_attribute requires to think about the pros and cons in the forefront, because migrating the production data back to boolean attributes is awkward. Furthermore, when it comes to boolean attributes representing several states (especially when the combination of boolean attributes respresent those states), a state machine should be considered.
Further articles of interest:
Supported by Ruby 2.1.1 and Ruby on Rails 3.2.19