Transparent manipulation of bitmask attributes for ActiveRecord, based on the bitmask-attribute gem, which has been dormant since 2009. This updated gem work with Rails 3 and up (including Rails 3.1).
The best way to install is with RubyGems:
$ [sudo] gem install bitmask_attributes
Or better still, just add it to your Gemfile:
Simply declare an existing integer column as a bitmask with its possible values.
class User < ActiveRecord::Base bitmask :roles, :as => [:writer, :publisher, :editor, :proofreader] end
You can then modify the column using the declared values without resorting to manual bitmasks.
user = User.create(:name => "Bruce", :roles => [:publisher, :editor]) user.roles # => [:publisher, :editor] user.roles << :writer user.roles # => [:publisher, :editor, :writer]
It's easy to find out if a record has a given value:
user.roles?(:editor) # => true
You can check for multiple values (uses an `and` boolean):
user.roles?(:editor, :publisher) # => true user.roles?(:editor, :proofreader) # => false
Or, just check if any values are present:
user.roles? # => true
You can get the list of values for any given attribute:
User.values_for_roles # => [:writer, :publisher, :editor, :proofreader]
A couple useful named scopes are also generated when you use `bitmask`:
User.with_roles # => (all users with roles) User.with_roles(:editor) # => (all editors) User.with_roles(:editor, :writer) # => (all users who are BOTH editors and writers) User.with_any_roles(:editor, :writer) # => (all users who are editors OR writers) User.with_exact_roles(:writer) # => (all users who are ONLY writers) User.with_exact_roles(:writer, :editor) # => (all users who are BOTH editors and writers and nothing else)
Find records without any bitmask set:
User.without_roles # => (all users without a role) User.no_roles # => (all users without a role)
Find records without a specific attribute.
User.without_roles(:editor) # => (all users who are not editors)
Note that “without_” only supports a single attribute argument, and the “no_” method does not support arguments. And “with_exact_” without arguments is alias for “no_”
You can add your own methods to the bitmasked attributes (similar to named scopes):
bitmask :other_attribute, :as => [:value1, :value2] do def worked? true end end user = User.first user.other_attribute.worked? # => true
Handling null values
By default, bitmasks support the potential for the underlying integer value to be null. However, if you have created a field that is guaranteed never to be null, you can simplify the SQL query conditions by declaring “:null => false” in the definition:
bitmask :never_null_attributes,:as => [:value1, :value2], :null => false
Warning: Modifying possible values
IMPORTANT: Once you have data using a bitmask, don't change the order of the values, remove any values, or insert any new values in the `:as` array anywhere except at the end. You won't like the results.
Create a branch (`git checkout -b new-feature`)
Make your changes
Run the tests (`bundle install` then `bundle exec rake`)
Commit your changes (`git commit -am “Created new feature”`)
Push to the branch (`git push origin new-feature`)
Create a pull request from your branch.
Promote it. Get others to drop in and +1 it.
Thanks to Bruce Williams and the following contributors of the bitmask-attribute plugin:
Copyright © 2007-2009 Bruce Williams & 2011 Joel Moss. See LICENSE for details.