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

我的问题的简短版本

在Rails ActiveRecord中,如果我有一个布尔字段并且我给它分配了类似“ abc ”或2东西,那么它会立即转换为false 。 值1truenil保持为nil 。 为什么会这样? 我在哪里可以找到解释此行为的Rails文档(或Ruby文档)?

我的问题的长版本

我很难理解Rails如何处理为Rails模型中的Boolean字段赋值的尝试。 例如,假设我有一个Website模型,其中包含一个名为:domainString字段和一个名为:can_sslBoolean字段。

我的迁移看起来像这样:

 class CreateWebsites  false t.timestamps end end end 

在我的模型文件中,我添加了一些validation规则,所以它看起来像这样:

 class Website  true validates :can_ssl, :inclusion => { :in => [true, false] } end 

很简单。 基于我所做的,我期待 :can_ssl只能设置为值truefalse ,而不是其他任何东西。 还有其他什么会导致valid?false

但是一旦我开始在控制台中玩游戏,我注意到,早在实际的赋值语句中,我提供的值正在重新转换为truefalse (或nil )。 有关如何将值转换为Boolean值的规则是什么?

控制台的示例:

 w = Website.new w.domain = 'stackoverflow.com' w.can_ssl = true w.can_ssl # => true w.valid? # => true w.can_ssl = nil w.can_ssl # => nil w.valid? # => false (so far so good) w.can_ssl = 'abc' w.can_ssl # => false (How did 'abc' become the value false?) w.valid? # => true w.can_ssl = 1 w.can_ssl # => true (I guess it makes sense that 1 casts to true) w.valid? # => true w.can_ssl = 2 w.can_ssl # => false (But anything other than 1 casts to false?) w.valid? # => true 

所以,根据我迄今所做的工作,我我可以得出以下结论:

  • 将值1true赋给Boolean字段时,该值将立即转换为true ,然后分配。
  • nil分配给Boolean字段时,该字段实际上分配为nil
  • 在分配任何其他内容(例如String或任何不是1 )时,该值将立即转换为false

我理解正确吗? 我错过了什么吗?

我很难在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_VALUES定义为

 #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”是因为流行的DBMS像MySql和PostgreSql,它们分别存储为0/1和“f”/“t”。

值得注意的是,这与通过Ruby / Rails中的“if”测试之间的区别,即“truthy”或“falsy”的值(“falsy”值将失败,如果测试,“truthy”值将通过它) 。

在Ruby中, nilfalse是“falsy”,而字面上的任何其他东西(包括0,空数组,空字符串,空哈希等)都是“真实的”。 因此,在ruby中被视为真实/虚假的内容与在布尔数据库列中保存为真/假的内容之间存在巨大差异。

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

  • e01a46f (2014-10-17)
  • a502703 (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 

常量ConnectionAdapters::Column::FALSE_VALUES定义如下:

 [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set 

如果某个值不是空字符串且不在其中,则会将其强制转换为true

此更改将在Rails 5.0上生效。

这是Ruby的东西,而不是Rails的东西。 布尔是“真实的”。 这里有一篇非常有用的文章。 https://gist.github.com/jfarmer/2647362