String "true" and "false" to boolean
Solution 1
As far as i know there is no built in way of casting strings to booleans,
but if your strings only consist of 'true'
and 'false'
you could shorten your method to the following:
def to_boolean(str)
str == 'true'
end
Solution 2
ActiveRecord provides a clean way of doing this.
def is_true?(string)
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(string)
end
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
has all of the obvious representations of True values as strings.
Solution 3
Security Notice
Note that this answer in its bare form is only appropriate for the other use case listed below rather than the one in the question. While mostly fixed, there have been numerous YAML related security vulnerabilities which were caused by loading user input as YAML.
A trick I use for converting strings to bools is YAML.load
, e.g.:
YAML.load(var) # -> true/false if it's one of the below
YAML bool accepts quite a lot of truthy/falsy strings:
y|Y|yes|Yes|YES|n|N|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF
Another use case
Assume that you have a piece of config code like this:
config.etc.something = ENV['ETC_SOMETHING']
And in command line:
$ export ETC_SOMETHING=false
Now since ENV
vars are strings once inside code, config.etc.something
's value would be the string "false"
and it would incorrectly evaluate to true
. But if you do like this:
config.etc.something = YAML.load(ENV['ETC_SOMETHING'])
it would be all okay. This is compatible with loading configs from .yml files as well.
Solution 4
There isn't any built-in way to handle this (although actionpack might have a helper for that). I would advise something like this
def to_boolean(s)
s and !!s.match(/^(true|t|yes|y|1)$/i)
end
# or (as Pavling pointed out)
def to_boolean(s)
!!(s =~ /^(true|t|yes|y|1)$/i)
end
What works as well is to use 0 and non-0 instead of false/true literals:
def to_boolean(s)
!s.to_i.zero?
end
Solution 5
ActiveRecord::Type::Boolean.new.type_cast_from_user
does this according to Rails' internal mappings ConnectionAdapters::Column::TRUE_VALUES
and ConnectionAdapters::Column::FALSE_VALUES
:
[3] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("true")
=> true
[4] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("false")
=> false
[5] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("T")
=> true
[6] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("F")
=> false
[7] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("yes")
DEPRECATION WARNING: You attempted to assign a value which is not explicitly `true` or `false` ("yes") to a boolean column. Currently this value casts to `false`. This will change to match Ruby's semantics, and will cast to `true` in Rails 5. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to `false`. (called from <main> at (pry):7)
=> false
[8] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("no")
DEPRECATION WARNING: You attempted to assign a value which is not explicitly `true` or `false` ("no") to a boolean column. Currently this value casts to `false`. This will change to match Ruby's semantics, and will cast to `true` in Rails 5. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to `false`. (called from <main> at (pry):8)
=> false
So you could make your own to_b
(or to_bool
or to_boolean
) method in an initializer like this:
class String
def to_b
ActiveRecord::Type::Boolean.new.type_cast_from_user(self)
end
end
davidb
I'm an IT-specialist from germany who's generally doing Debian Linux/Win2012/Win2016 server administration and Ruby On Rails development for a research institute at the university of Bremen. Im also very interested in security related topics especial in network, wireless and web application security.
Updated on July 08, 2022Comments
-
davidb almost 2 years
I have a Rails application and I'm using jQuery to query my search view in the background. There are fields
q
(search term),start_date
,end_date
andinternal
. Theinternal
field is a checkbox and I'm using theis(:checked)
method to build the url that is queried:$.getScript(document.URL + "?q=" + $("#search_q").val() + "&start_date=" + $("#search_start_date").val() + "&end_date=" + $("#search_end_date").val() + "&internal=" + $("#search_internal").is(':checked'));
Now my problem is in
params[:internal]
because there is a string either containing "true" or "false" and I need to cast it to boolean. Of course I can do it like this:def to_boolean(str) return true if str=="true" return false if str=="false" return nil end
But I think there must be a more Ruby'ish way to deal with this problem! Isn't there...?
-
Pavling over 12 yearsyou don't need the guard "s and ..." if you use "!!(s =~ /regex_here/)" because "nil =~ /anything/" returns nil.
-
Marcel Jackwerth over 12 yearsAh indeed. I added it but kept the old as well, as I think the
.match
is a little bit easier to read. -
AMTourky over 10 yearsjust a little modification str == 'true' || str = '1'
-
JEMaddux over 10 yearsperhaps str.downcase == 'true' for completeness
-
Mike Atlas over 10 yearsEven simpler, just use
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(string)
(source) apidock.com/rails/v3.0.9/ActiveRecord/ConnectionAdapters/Column/… -
Satya Kalluri almost 10 yearsYes, in the latest versions!
-
Krease almost 10 yearsI definitely wouldn't want to have a
to_bool
function returnnil
; that seems wrong. Other conversion functions don't do this:"a".to_i
returns0
, notnil
-
AlexChaffee about 9 years
ActiveRecord::Type::Boolean.new.type_cast_from_user("true")
=> trueActiveRecord::Type::Boolean.new.type_cast_from_user("T")
=> true -
Teoulas over 8 yearsThat's good if the passed string is under your control. In this question's case, the provided values come from the user's browser and as such, they should be considered unsafe. YAML allows you to serialize/deserialize any Ruby object and this is potentially dangerous. There have been numerous incidents: google.com/webhp?q=rails+yaml+vulnerability
-
Halil Özgür over 8 years@Teoulas, I completely agree with you. In fact, I'm adding a notice so people don't use this in an insecure way.
-
davidb over 8 yearsThats because This solution is a security Desaster. :D
-
Ben Aubin over 8 yearsThe problem with this solution is user input - if someone types
to_boolean("ActiveRecord::Base.connection.execute('DROP TABLE *')")
, it'll destroy your database (and return true!). Have fun :D -
povess over 8 yearsGood points. I wasn't thinking of the context. I was thinking the least amount of characters to implement. :)
-
divideByZero over 7 yearsbe aware though, ActiveRecord::Type::Boolean.new.cast("42") returns true
-
divideByZero over 7 yearsFalse value list has been moved to ActiveModel::Type::Boolean in Rails 5
-
Pascal over 7 years@AMTourky shouldn't it be str == 'true' || str == '1' with two "==" ?
-
7urkm3n over 7 years@Lowryder Yes! if using default check_box.
-
Dave Burt over 7 yearsIt is ActiveRecord::Type::Boolean.new.cast(value) in Rails 5 (see CWitty below)
-
Lyndsy Simon over 7 years
ActiveModel::Type::Boolean
seems like a much more suitable path - whileActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
contained "truthy" values, one could argue that it's only incidentally the case, and that values that should be considered truthy for that specific use case but not others could be included. On the other hand,ActiveModel::Type::Boolean
is apparently designed to be used in a generic way. -
Fernando Cordeiro almost 4 yearsAn easy fix for said vulnerability:
bool = nil; bool = eval(str) if ["true", "false"].include?(str)
Just thought I should add for the sake of clarifications.