Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Rails, what is the best way to store multiple boolean attributes in a model?

I have a model House that has many boolean attributes, like has_fireplace, has_basement, has_garage, and so on. House has around 30 such boolean attributes. What is the best way to structure this model for efficient database storage and search?

I would like to eventually search for all Houses that have a fireplace and a garage, for example.

The naive way, I suppose, would be to simply add 30 boolean attributes in the model that each corresponds to a column in the database, but I'm curious if there's a Rails best practice I'm unaware of.

like image 677
Sanjay Avatar asked Sep 09 '10 23:09

Sanjay


4 Answers

Your 'naive' assumption is correct - the most efficient way from a query speed and productivity perspective is to add a column for each flag.

You could get fancy as some others have described, but unless you're solving some very specific performance problems, it's not worth the effort. You'd end with a system that's harder to maintain, less flexible and that takes longer to develop.

like image 78
Joshua Avatar answered Nov 07 '22 16:11

Joshua


For that many booleans in a single model you might consider using a single integer and bitwise operations to represent, store and retrieve values. For example:

class Model < ActveRecord::Base
  HAS_FIREPLACE = (1 << 0)
  HAS_BASEMENT  = (1 << 1)
  HAS_GARAGE    = (1 << 2)

  ...
end

Then some model attribute called flags would be set like this:

flags |= HAS_FIREPLACE
flags |= (HAS_BASEMENT | HAS_GARAGE)

And tested like this:

flags & HAS_FIREPLACE
flags & (HAS_BASEMENT | HAS_GARAGE)

which you could abstract into methods. Should be pretty efficient in time and space as an implementation

like image 7
bjg Avatar answered Nov 07 '22 15:11

bjg


I suggest the flag_shih_tzu gem. It helps you store many boolean attributes in one integer column. It gives you named scopes for each attribute and a way to chain them together as active record relations.

like image 5
Robin Bortlík Avatar answered Nov 07 '22 16:11

Robin Bortlík


Here's another solution.

You could make a HouseAttributes model and set up a two way has_and_belongs_to_many association

# house.rb
class House
  has_and_belongs_to_many :house_attributes
end

# house_attribute.rb
class HouseAttribute
  has_and_belongs_to_many :houses
end

Then each attribute for a house would be a database entry.

Don't forget to set up your join table on your database.

like image 4
edgerunner Avatar answered Nov 07 '22 15:11

edgerunner