I support the flag_shih_tzu.
Best practice: for each column used for flags, no more than 16 flags should be set for performance reasons. You will find that performance suffers too much from columns containing more than 16 flags.
Workaround: A single table can have multiple columns of flags.
I would create a design as follows:
class Foo ... has_flags 1 => :is_a1, # ... snip ... 16 => :is_a16, :column => 'flag_col_a' has_flags 1 => :is_b1, # ... snip ... 16 => :is_b16, :column => 'flag_col_b' has_flags 1 => :is_c1, # ... snip ... 16 => :is_c16, :column => 'flag_col_c' has_flags 1 => :is_d1, # ... snip ... 16 => :is_d16, :column => 'flag_col_d' end
Now that you have an instance of Foo:
foo = Foo.new foo.is_d16 = false foo.save
Now you can restore foo as follows:
Foo.not_is_d16 # => [foo]
And if you also want to check other flags in the same query, you must combine the conditions (in a bitwise optimized way) as follows:
Foo.chained_flags_with(:not_is_d16, :is_d1, :is_d4, :not_is_d11, :is_d14)
Now for the giant reservation! If you want to use the four columns together, they must be in separate parts of the SQL WHERE clause and, therefore, in different active record relationships.
Important Chain flags can only be associated with flags from a single column.
Foo. chained_flags_with(:not_is_a1, :is_a2). # from flag_col_a chained_flags_with(:not_is_b3, :is_b4). # from flag_col_b chained_flags_with(:not_is_c8, :is_c11). # from flag_col_c chained_flags_with(:not_is_d13, :is_d14) # from flag_col_d
Personally, I never go past 8 flags per column and break my flags into as many columns as I need.
Recommendation : combine flags for properties that will be queried together in one column to make the best use of bitwise arithmetic.