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?
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.
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With