Short version of my question
In Rails ActiveRecord, if I have a Boolean field and I assign it something like \"abc\" or 2, the
The behavior of boolean columns changed with two commits:
The new rule is very simple. See the code below:
module ActiveRecord
module Type
class Boolean < Value # :nodoc:
def type
:boolean
end
private
def cast_value(value)
if value == ''
nil
else
!ConnectionAdapters::Column::FALSE_VALUES.include?(value)
end
end
end
end
end
The constant ConnectionAdapters::Column::FALSE_VALUES is defined as follows:
[false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
If a value is not an empty string and is not among them, it will be cast to true.
This change will become effective on the Rails 5.0.
This is a Ruby thing rather than a Rails thing. Boolean is "truthy". There's a pretty useful article on it here. https://gist.github.com/jfarmer/2647362
This is done in the bowels of ActiveRecord: specifically with
ActiveRecord::ConnectionAdapters::Column.value_to_boolean
at least in my version of rails (it may be somewhere slightly different in more recent versions).
Here's the source in my version
# File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 144
144: def value_to_boolean(value)
145: if value.is_a?(String) && value.blank?
146: nil
147: else
148: TRUE_VALUES.include?(value)
149: end
150: end
where TRUE_VALUES is defined as
#activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb:10:
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
1, 0, "f" and "t" are there because of popular DBMS's like MySql & PostgreSql, which store bools as 0/1 and "f"/"t" respectively.
It's worth noting the difference between this and what passes an "if" test in Ruby/Rails, ie values that are "truthy" or "falsy" ("falsy" values will fail an if test, "truthy" values will pass it).
In Ruby, nil and false are "falsy" and literally anything else (including 0, empty arrays, empty strings, empty hashes etc) is "truthy". So, there's a massive disparity between what is deemed truthy/falsy in ruby and what is saved as true/false to a boolean database column.