Ruby on rails 在Rails ActiveRecord中分配给布尔字段时,如何转换值?

Ruby on rails 在Rails ActiveRecord中分配给布尔字段时,如何转换值?,ruby-on-rails,activerecord,boolean,Ruby On Rails,Activerecord,Boolean,我问题的简短版本 在Rails ActiveRecord中,如果我有一个布尔字段,并将其赋值为“abc”或2,那么它会立即转换为false。值1被转换为true,而nil保持为nil。为什么会这样?在哪里可以找到解释这种行为的Rails文档(或Ruby文档) 我的问题的长篇版本 我很难理解Rails是如何处理为Rails模型中的Boolean字段赋值的尝试的。例如,假设我有一个网站模型,它有一个字符串字段,名为:domain,还有一个布尔字段,名为:can\u ssl 我的迁移如下所示: cla

我问题的简短版本

在Rails ActiveRecord中,如果我有一个布尔字段,并将其赋值为“
abc
”或
2
,那么它会立即转换为
false
。值
1
被转换为
true
,而
nil
保持为
nil
。为什么会这样?在哪里可以找到解释这种行为的Rails文档(或Ruby文档)

我的问题的长篇版本

我很难理解Rails是如何处理为Rails模型中的
Boolean
字段赋值的尝试的。例如,假设我有一个
网站
模型,它有一个
字符串
字段,名为
:domain
,还有一个
布尔
字段,名为
:can\u ssl

我的迁移如下所示:

class CreateWebsites < ActiveRecord::Migration
  def change
    create_table :websites do |t|
      t.string :domain
      t.boolean :can_ssl, :default => false

      t.timestamps
    end
  end
end
class Website < ActiveRecord::Base
  validates :domain, :presence => true
  validates :can_ssl, :inclusion =>  { :in => [true, false] }
end
因此,根据我迄今为止所做的工作,我认为我可以得出以下结论:

  • 将值
    1
    true
    分配给
    布尔值
    字段时,该值将立即转换为
    true
    ,然后进行分配
  • nil
    赋值给
    Boolean
    字段时,该字段实际上被赋值为
    nil
  • 当分配任何其他值(例如
    字符串
    或任何非
    1
    的数字)时,该值将立即转换为
我理解对了吗?我遗漏了什么吗


我很难在Rails中找到
Boolean
字段类型的文档,这可以让我对此进行澄清。

这是在ActiveRecord的内部完成的:特别是使用

ActiveRecord::ConnectionAdapters::Column.value_to_boolean
至少在我的rails版本中是这样(在较新的版本中可能会略有不同)

这是我版本中的源代码

    # 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
其中,TRUE_值定义为

#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”和“t”之所以存在,是因为MySql和PostgreSql等流行的DBMS分别将布尔值存储为0/1和“f”/“t”

值得注意的是,这与Ruby/Rails中通过“if”测试的内容之间的区别,即“truthy”或“falsy”值(“falsy”值将通过if测试,“truthy”值将通过测试)


在Ruby中,
nil
false
都是“falsy”,其他任何东西(包括0、空数组、空字符串、空哈希等)都是“truthy”。因此,在ruby中被视为truty/falsy的内容与保存为布尔数据库列的true/false的内容之间存在着巨大的差异。

这是ruby的东西,而不是Rails的东西。布尔值是“真实的”。这里有一篇非常有用的文章

布尔列的行为随两次提交而更改:

  • (2014-10-17)
  • (2015-01-04)
新规则非常简单。请参阅下面的代码:

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
如果某个值不是空字符串且不在其中,则该值将转换为
true


此更改将在Rails 5.0上生效。

这不是他问的问题:他问的是“为什么将'abc'保存为布尔列的“false”。“abc”在ruby中是真实的,这似乎是一个矛盾。
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
[false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set