29

Is there a "cool-kid-approved" replacement for ActiveRecord::ConnectionAdapters::Column.value_to_boolean in rails 3.2?

Ilya Lavrov
  • 2,810
  • 3
  • 20
  • 37
Chris B
  • 764
  • 1
  • 7
  • 19
  • 1
    Can you give a use case, or some more details? You can always use `!!` which would change any value to a boolean. Eg. `!!nil` would be false, and `!!1` would be true. – jokklan Jun 19 '13 at 08:16
  • 1
    While `[false, 0, '0', 'f', 'F', 'false', 'FALSE'].map { |v| !!v }` yields `[false, true, true, true, true, true, true]`. It's obviously not a replacement. – Gunchars May 05 '14 at 21:02

4 Answers4

109

In Rails 4.2, this looks like a possible way to do it:

 ActiveRecord::Type::Boolean.new.type_cast_from_database(value)

Which under the covers is going to do this

if value == ''
  nil
else
  ConnectionAdapters::Column::TRUE_VALUES.include?(value)
end

Or in Rails 5:

 ActiveRecord::Type::Boolean.new.cast(value)

Which seems to end up here:

  def cast_value(value)
    if value == ''
      nil
    else
      !FALSE_VALUES.include?(value)
    end
  end
John Naegle
  • 8,077
  • 3
  • 38
  • 47
  • 3
    It seems like `ActiveRecord::Type::Boolean.new.type_cast_from_user(value)` would be a more appropriately named alternative (with the same functionality) https://github.com/rails/rails/blob/v4.2.3/activerecord/lib/active_record/type/value.rb#L33 – Manuel Meurer Jul 24 '15 at 19:09
  • 7
    For Rails 5, today I had to do ActiveRecord::Type::Boolean.new.cast rather than type_cast. – Thibaut Barrère Aug 23 '16 at 19:58
  • Thanks, will update. I haven't been on Rails 5 for a bit. – John Naegle Aug 24 '16 at 14:44
  • ` ActiveRecord::Type::Boolean.new.cast(value)` – Jake Oct 14 '16 at 19:10
  • There's a little gotcha: `value_to_boolean` used to convert nil to false, `type_cast_from_database` does not (it returns nil in that case). This can lead to errors if you have eg. non-null constraints. – fabi Mar 29 '17 at 06:45
  • Beware if you're converting symbols, as `:''` is cast to `true` (I'm converting a boolean column that can be nil to a localized string). – Goulven Jul 23 '21 at 15:17
12

As jokklan mentioned in the comments, the answer depends on what you want to do with it? Do you want to accepts all kinds of strings and turn them into a real boolean? Or do you control the submitting end as well and can you be more strict?

From strict to more magic:

bang bang

The double bang method converts any object to a real boolean. The first bang turns it into it's opposite, the second to it's proper boolean value.

Basically, nil and false will become false, everything else will become true.

!!nil     # => false
!!false   # => false
!!0       # => true
!!true    # => true
!!""      # => true
!!"false" # => true
!![]      # => true

Good for exporting to json, but not really needed when kept inside Ruby.

Object#present?

From ActiveSupport and the opposite of blank?:

nil.present?     # => false
false.present?   # => false
0.present?       # => true
"false".present? # => true
"".present?      # => false
[].present?      # => false

Array#include?

Specify special strings that are falsy, or truthy to you:

not [nil, false, 0, '0', 'f', 'F', 'false', 'FALSE'].include?(value.presence)

Or the other way round:

[true, 1, '1', 't', 'T', 'true', 'TRUE'].include?(value)

These are handy if you are handling form submissions with checkboxes, or handling external input and you want to be more lenient. You can of course decide for yourself what you want to accept.

iain
  • 16,204
  • 4
  • 37
  • 41
  • Thanks for all the info. Looks like `!!` was the syntactic sugar I was looking for.... – Chris B Jun 25 '13 at 04:43
  • 4
    Just in case it wasn't apparent from iain's answer, if you want string `"false"` to return boolean `false` when using `!!`, as in `!!"false"`, it will not. Instead it'll return `true` and you'll have a yucky bug to find. If you're in rails really only checking for presence, as iain's answer would, you're really better off using more explicit `#present?` or `#blank?` methods from Active Support Core Extensions. – Chad M Sep 20 '16 at 07:22
1

ActiveRecord::Type::Boolean.new.type_cast_from_database(value) return nil if the value is nil/empty('').

ActiveRecord::Type::Boolean.new.type_cast_from_database(nil) # => nil ActiveRecord::Type::Boolean.new.type_cast_from_database('') # => nil

I would prefer !! with ActiveRecord::Type::Boolean.new.type_cast_from_database(value) for converting input value to boolean

!!ActiveRecord::Type::Boolean.new.type_cast_from_database(nil) # => false !!ActiveRecord::Type::Boolean.new.type_cast_from_database('') # => false

geekdev
  • 1,192
  • 11
  • 15
0

It appears that value_to_boolean isn't really deprecated in Rails 4 http://www.rubydoc.info/docs/rails/ActiveRecord/ConnectionAdapters/Column.value_to_boolean

Ev Dolzhenko
  • 6,100
  • 5
  • 38
  • 30