ブール値への文字列「true」および「false」


85

Railsアプリケーションがあり、jQueryを使用してバックグラウンドで検索ビューを照会しています。そこフィールドは、q(検索語)、 start_dateend_dateinternal。このinternalフィールドはチェックボックスであり、このis(:checked)メソッドを使用して、照会されるURLを作成しています。

$.getScript(document.URL + "?q=" + $("#search_q").val() + "&start_date=" + $("#search_start_date").val() + "&end_date=" + $("#search_end_date").val() + "&internal=" + $("#search_internal").is(':checked'));

params[:internal]「true」または「false」を含む文字列があり、ブール値にキャストする必要があるため、問題が発生しました。もちろん、私はこのようにそれを行うことができます:

def to_boolean(str)
     return true if str=="true"
     return false if str=="false"
     return nil
end

しかし、私はこの問題に対処するためのもっとルビーっぽい方法があるに違いないと思います!ありませんか…?

回答:


133

私の知る限り何のブール値に文字列をキャストする方法であっ構築されている知っていないが、としてあなたの文字列だけで構成されている場合'true'と、'false'次のあなたの方法を短縮できます。

def to_boolean(str)
  str == 'true'
end

8
ほんの少しの変更str == 'true' || str = '1'
AMTourky 2013年

30
おそらくstr.downcase == 'true'完全性のために
JEMaddux 2013年

@AMTourkyはstr == 'true'であってはなりません|| str == '1' with two "=="?
パスカル

@Lowryderはい!デフォルトのcheck_boxを使用する場合。
7urkm3n 2016

49

ActiveRecordはこれを行うためのクリーンな方法を提供します。

def is_true?(string)
  ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(string)
end

ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES True値の明白な表現をすべて文字列として持っています。


16
さらに簡単に、ActiveRecord::ConnectionAdapters::Column.value_to_boolean(string)(ソース)apidock.com/rails/v3.0.9/ActiveRecord/ConnectionAdapters/Column/を
Mike Atlas

はい、最新バージョンでは!
Satya Kalluri 2014

6
ActiveRecord::Type::Boolean.new.type_cast_from_user("true")=> true ActiveRecord::Type::Boolean.new.type_cast_from_user("T")=> true
AlexChaffee 2015

Falseの値リストは、Railsの5にActiveModel ::タイプ::ブールに移動されました
DIVIDEBYZERO

ActiveModel::Type::BooleanActiveRecord::ConnectionAdapters::Column::TRUE_VALUES「真実の」値が含まれている一方で、それは偶然のケースであり、その特定のユースケースでは真実であると見なされるべきであるが他のユースケースではないと見なされるべき値を含めることができると主張することができます。一方、ActiveModel::Type::Boolean一般的な方法で使用するように設計されているようです。
Lyndsy Simon 2017

24

セキュリティに関するお知らせ

そのままの形でのこの回答は、質問のユースケースではなく、以下にリストされている他のユースケースにのみ適切であることに注意してください。ほとんど修正されていますが、ユーザー入力をYAMLとしてロードすることによって引き起こされたYAML関連のセキュリティの脆弱性が多数あります。


文字列をboolに変換するために使用するトリックはYAML.load、次のとおりです。

YAML.load(var) # -> true/false if it's one of the below

YAML boolは、非常に多くの真実/偽の文字列を受け入れます。

y|Y|yes|Yes|YES|n|N|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF

別のユースケース

次のような構成コードがあると仮定します。

config.etc.something = ENV['ETC_SOMETHING']

そしてコマンドラインで:

$ export ETC_SOMETHING=false

今以来ENVVARSは、内部コード一度文字列である、config.etc.somethingの値は文字列になり"false"、それが間違っに評価されますtrue。しかし、あなたがこれを好きなら:

config.etc.something = YAML.load(ENV['ETC_SOMETHING'])

それはすべて大丈夫でしょう。これは、.ymlファイルからの設定の読み込みとも互換性があります。


1
渡された文字列があなたの管理下にある場合、それは良いことです。この質問の場合、提供された値はユーザーのブラウザからのものであるため、安全ではないと見なす必要があります。YAMLを使用すると、Rubyオブジェクトをシリアル化/逆シリアル化できますが、これは潜在的に危険です。多くの事件がありました:google.com/webhp
q

1
@Teoulas、私はあなたに完全に同意します。実際、私は通知を追加しているので、人々はこれを安全でない方法で使用しません。
ハリル・Özgür

16

これを処理するための組み込みの方法はありません(ただし、actionpackにはそのためのヘルパーがある場合があります)。私はこのようなことをアドバイスします

def to_boolean(s)
  s and !!s.match(/^(true|t|yes|y|1)$/i)
end

# or (as Pavling pointed out)

def to_boolean(s)
  !!(s =~ /^(true|t|yes|y|1)$/i)
end

同様に機能するのは、false / trueリテラルの代わりに0と非0を使用することです。

def to_boolean(s)
  !s.to_i.zero?
end

3
「!!(s =〜/ regex_here /)」を使用する場合、「nil =〜/ anything /」はnilを返すため、ガード「s and ...」は必要ありません。
2011年

ああ、確かに。私はそれを追加しましたが.match、少し読みやすいと思うので、古いものも保持しました。
Marcel Jackwerth 2011年

7

ActiveRecord::Type::Boolean.new.type_cast_from_userRailsの内部マッピングに従ってこれをConnectionAdapters::Column::TRUE_VALUES行いConnectionAdapters::Column::FALSE_VALUESます。

[3] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("true")
=> true
[4] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("false")
=> false
[5] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("T")
=> true
[6] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("F")
=> false
[7] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("yes")
DEPRECATION WARNING: You attempted to assign a value which is not explicitly `true` or `false` ("yes") to a boolean column. Currently this value casts to `false`. This will change to match Ruby's semantics, and will cast to `true` in Rails 5. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to `false`. (called from <main> at (pry):7)
=> false
[8] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("no")
DEPRECATION WARNING: You attempted to assign a value which is not explicitly `true` or `false` ("no") to a boolean column. Currently this value casts to `false`. This will change to match Ruby's semantics, and will cast to `true` in Rails 5. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to `false`. (called from <main> at (pry):8)
=> false

したがって、次のような初期化子で独自のto_b(またはto_boolまたはto_boolean)メソッドを作成できます。

class String
  def to_b
    ActiveRecord::Type::Boolean.new.type_cast_from_user(self)
  end
end

2
Rails5のActiveRecord :: Type :: Boolean.new.cast(value)です(下記のCWittyを参照)
Dave Burt


6

Rails 5では、これを使用ActiveRecord::Type::Boolean.new.cast(value)してブール値にキャストできます。


1
意識しかし、ActiveRecordの::タイプ:: Boolean.new.cast( "42")がtrueを返すこと
DIVIDEBYZERO

3

そのようなものはRubyに組み込まれているとは思いません。Stringクラスを再度開き、そこにto_boolメソッドを追加できます。

class String
    def to_bool
        return true if self=="true"
        return false if self=="false"
        return nil
    end
end

次に、次のように、プロジェクトのどこでも使用できます。 params[:internal].to_bool


2
私は間違いなくto_bool関数を返したくありませんnil; それは間違っているようです。他の変換関数はこれを行いません:"a".to_i戻り値0ではなくnil
Krease 2014

3

おそらくstr.to_s.downcase == 'true'完全性のために。その場合、strがnilまたは0であっても、何もクラッシュしません。


2

Virtusのソースコードを見ると、私はおそらく次のようなことをするでしょう:

def to_boolean(s)
  map = Hash[%w[true yes 1].product([true]) + %w[false no 0].product([false])]
  map[s.to_s.downcase]
end

1

internalそれが真である場合にのみURLに追加することを検討できます。チェックボックスがチェックされておらず、追加しない場合params[:internal]は、nilRubyでfalseと評価され、。

私はあなたが使用している特定のjQueryにそれほど精通していませんが、URL文字列を手動で作成するよりも、必要なものを呼び出すためのよりクリーンな方法はありますか?あなたが見ていた持っている$get$ajax


1

Stringクラスに追加して、to_booleanのメソッドを持つことができます。次に、「true」.to_booleanまたは「1」.to_booleanを実行できます。

class String
  def to_boolean
    self == 'true' || self == '1'
  end
end

-5

この単純な解決策を誰も投稿していないことに驚いています。これは、文字列が「true」または「false」になる場合です。

def to_boolean(str)
    eval(str)
end

4
これは、このソリューションがセキュリティデザスターであるためです。:D
davidb 2015

1
このソリューションの問題はユーザー入力です-誰かが入力to_boolean("ActiveRecord::Base.connection.execute('DROP TABLE *')")すると、データベースが破壊されます(そしてtrueが返されます!)。楽しんでください:D
ベンオービン2015

良い点。私は文脈について考えていませんでした。実装する文字の量を最小限に抑えることを考えていました。:)
2016年

上記の脆弱性の簡単な修正:bool = nil; bool = eval(str) if ["true", "false"].include?(str)明確にするために追加する必要があると考えました。
フェルナンドコルデイロ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.