We often need to store several booleans to determine a user's settings. Bitmasks are a good economic way to do so. The idea is to use a single integer where each bit represents one such boolean. This is better than saving each individual settings in a different database column.
Choose bit positions for each settings. Lets say we want to store notification settings.
NEWSLETTER = 0 COMMENTS = 1 FOLLOWER = 2
Now let's turn off all settings:
user.settings = 0
Now let's turn on comment notifications:
user.settings |= (1 << COMMENTS)
Let's see how it looks like in binary:
user.settings.to_s(2) >>> "10"
The bit at position 1 (
COMMENTS) was set to 1 while the rest hasn't changed.
1 << N places (shifts) the value 1 to the position N so that e.g.:
(1 << 4).to_s(2) >>> "10000"
& are the usual OR and AND operators but applied at a bit level so that :
(1 << 4 | 1 << 2).to_s(2) >>> "10100"
We see that
a |= 1 << N turns ON the N-positioned bit in the integer
~ inverts all the bits in a variable so that:
(~0b1010).to_s(2) >>> "-110"
Which is all bits set to 1 except bit 1 and bit 3 if we talk about signed integers.
To turn a bit OFF, simply do
user.settings &= ~(1 << COMMENTS)
~(1 << COMMENTS) will have all bits ON except the one at position
To check if a specific settings is ON, simply check
user.settings & (1 << COMMENTS) > 0