Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails scope with boolean

When you're using a boolean in Rails with Active Record, and you ask (say) visible?, it checks the column for whether it is true or not. If it is false or nil, visible? will return false.

How do you scope a boolean to ask if the ? method would return false? I have this:

scope :visible, where(hide: [nil, false])

but am wondering if there is a cleaner way. Is there a way to write this scope without explicitly saying both nil and false? If we were after the opposite, we could just write

scope :invisible, where(hide: true)

which seems cleaner. What's the best code for the visible scope?

like image 563
Peter Avatar asked Jul 03 '12 06:07

Peter


4 Answers

Use a default value on the column. This is good for two reasons: you have only two possible values in your DB, making your code easier. And booleans are either true or false, not nil, not maybe, not foobar. True and false. "I'd rather avoid having to get the DB strictly false/true though" is a moot argument for a boolean column.

If you need more than 2 states, use a state machine or something similar - then its not a boolean column/state anymore.

like image 91
Tanel Suurhans Avatar answered Oct 22 '22 19:10

Tanel Suurhans


As of Rails 4, you can accomplish this like so:

# This will give you any hidden records
scope :invisible, -> { where(hide: true) }

# And this will give you any records that aren't hidden – whether nil *or* false
scope :visible, -> { where.not(hide: true) }

Although Tanel's answer doesn't actually answer the question at hand, which is "What's the best code for the visible scope?", I would definitely echo what he said that a boolean column should always be either true or false.

Really, no database should even allow a column declared as boolean to be anything other than true or false because, otherwise, it's not truly boolean. But that's a separate can of worms. :-D

like image 42
jeffdill2 Avatar answered Oct 22 '22 17:10

jeffdill2


I'd go with:

scope :visible, -> { where(hide: false) }
scope :invisible, -> { where(hide: true) }

In SQL NULL represents a missing or unknown value so strictly speaking records with hide = NULL are neither visible nor invisible.

like image 40
Stefan Avatar answered Oct 22 '22 19:10

Stefan


Almost the same as Stefan's answer, a bit simplified:

scope :visible, where(hide: false)
scope :invisible, where(:hide)

It works for PostgreSQL, but I'm not sure will it work for other databases.

like image 40
denis.peplin Avatar answered Oct 22 '22 17:10

denis.peplin