How are values cast when assigning to a Boolean field in Rails ActiveRecord?

前端 未结 3 1288
醉酒成梦
醉酒成梦 2021-02-08 21:37

Short version of my question

In Rails ActiveRecord, if I have a Boolean field and I assign it something like \"abc\" or 2, the

相关标签:
3条回答
  • 2021-02-08 22:02

    The behavior of boolean columns changed with two commits:

    • e01a46f (2014-10-17)
    • a502703 (2015-01-04).

    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.

    0 讨论(0)
  • 2021-02-08 22:16

    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

    0 讨论(0)
  • 2021-02-08 22:24

    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.

    0 讨论(0)
提交回复
热议问题