2014-03-13 79 views
7

我的問題當分配給Rails ActiveRecord中的布爾字段時,如何賦值?

的短版在Rails ActiveRecord的,如果我有一個布爾字段,我給你類似爲「abc」或2,那麼它就會立即轉換爲false。價值1鑄造爲truenil保持爲nil。爲什麼會這樣?我在哪裏可以找到解釋此行爲的Rails文檔(或Ruby文檔)?

龍版我的問題

我難以理解的Rails如何處理嘗試分配在Rails模型值的Boolean領域。例如,假設我有一個Website模型,該模型的String字段和Boolean字段:can_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 

夠簡單。基於我所做的,我是期待: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 

那麼,根據什麼我迄今所做的,我想可以得出以下結論:

  • 當分配值1trueBoolean字段,該值將立即投射爲true,然後分配。
  • nil分配給Boolean字段時,該字段實際上被分配爲nil
  • 當分配其他任何東西(例如String或任何非1的數字)時,該值將立即變爲false

我的理解是否正確?我錯過了什麼?

我很難找到在Rails中的文檔Boolean字段類型,可以給我澄清這一點。至少在我的版本軌(它可能會在較新版本的地方略有不同),特別是與

ActiveRecord::ConnectionAdapters::Column.value_to_boolean 

回答

7

這在ActiveRecord的的腸子做。

下面是我的版本

# 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 ,它們將bools分別存儲爲0/1和「f」/「t」。

值得注意的是,它與通過Ruby/Rails中「if」測試的區別在於,即值「truthy」或「falsy」(「falsy」值將失敗if test,「truthy」values將通過它)。

在Ruby,nilfalse是 「falsy」 和字面任何其他(包括0,空數組,空字符串,空散列等)是 「truthy」。所以,在ruby中被認爲是truthy/falsy和被保存爲真/假的數據之間存在巨大的差異。

0

這是一個Ruby的東西,而不是Rails的東西。布爾是「真理」。這裏有一篇非常有用的文章。 https://gist.github.com/jfarmer/2647362

+0

這不是他問的問題:他問「爲什麼'abc'被保存爲」假「到布爾列」。 「abc」是紅寶石中的真理,這似乎是一個矛盾。 –

3

布爾列的行爲有兩個提交更改:

新規則很簡單。請參見下面的代碼:

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上生效。