Boole için "true" ve "false" dizesi


86

Bir Rails uygulamam var ve arama görünümümü arka planda sorgulamak için jQuery kullanıyorum. Orada alanlar q(arama teriminin), start_date, end_dateve internal. internalAlan bir onay kutusudur ve ben kullanıyorum is(:checked)sorgulanır url oluşturmak için yöntem:

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

Şimdi benim sorunum, params[:internal]çünkü "true" veya "false" içeren bir dizge var ve onu boolean'a çevirmem gerekiyor. Tabii ki bunu şu şekilde yapabilirim:

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

Ama bence bu problemi çözmenin daha Ruby'ce bir yolu olmalı! Yok mu ...?

Yanıtlar:


134

Bildiğim kadarıyla, dizeleri booleanlara aktarmanın yerleşik bir yolu yoktur, ancak dizeleriniz yalnızca içeriyorsa 'true've 'false'yönteminizi aşağıdakilere kısaltabilirseniz:

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

8
sadece küçük bir değişiklik str == 'true' || str = '1'
AMTourky

30
belki str.downcase == 'true' tamlık için
JEMaddux

@AMTourky str == 'true' olmamalıdır || str == '1' ile iki "=="?
Pascal

@Lowryder Evet! varsayılan check_box kullanılıyorsa.
7urkm3n

49

ActiveRecord bunu yapmanın temiz bir yolunu sağlar.

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

ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES Gerçek değerlerin tüm açık temsillerini dizeler olarak içerir.


16
Daha da basit, ActiveRecord::ConnectionAdapters::Column.value_to_boolean(string)(kaynak) apidock.com/rails/v3.0.9/ActiveRecord/ConnectionAdapters/Column/…
Mike Atlas

Evet, son versiyonlarda!
Satya Kalluri

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

Yanlış değer listesi Rails 5'te ActiveModel :: Type ::
Boolean'a

ActiveModel::Type::Booleançok daha uygun bir yol gibi görünmektedir - ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES"doğru" değerler içermekle birlikte, bunun sadece tesadüfen olduğu ve bu özel kullanım durumu için doğru olarak kabul edilmesi gereken ancak diğerlerinin dahil edilemeyeceği değerlerin dahil edilemeyeceği iddia edilebilir. Öte yandan, ActiveModel::Type::Booleangörünüşe göre genel bir şekilde kullanılmak üzere tasarlanmıştır.
Lyndsy Simon

24

Güvenlik Bildirimi

Çıplak haliyle bu cevabın, sorudaki cevap yerine yalnızca aşağıda listelenen diğer kullanım durumu için uygun olduğunu unutmayın. Çoğunlukla düzeltilse de, kullanıcı girişini YAML olarak yüklemenin neden olduğu YAML ile ilgili çok sayıda güvenlik açığı vardır.


Dizeleri boollere dönüştürmek için kullandığım bir numara YAML.load, örneğin:

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

YAML bool , oldukça fazla doğru / yanlış dizeyi kabul eder:

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

Başka bir kullanım durumu

Bunun gibi bir yapılandırma kodunuz olduğunu varsayalım:

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

Ve komut satırında:

$ export ETC_SOMETHING=false

ENVDeğişkenler bir zamanlar kod içinde dizeler olduğundan , config.etc.something's değeri dizge olur "false"ve yanlış olarak değerlendirilir true. Ama eğer böyle yaparsan:

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

her şey yoluna girecek. Bu, yapılandırmaların .yml dosyalarından yüklenmesiyle de uyumludur.


1
İletilen dizge sizin kontrolünüz altındaysa bu iyidir. Bu sorunun durumunda, sağlanan değerler kullanıcının tarayıcısından gelir ve bu nedenle güvenli olmadığı düşünülmelidir. YAML, herhangi bir Ruby nesnesini serileştirmenize / serisini kaldırmanıza izin verir ve bu potansiyel olarak tehlikelidir. Çok sayıda olay oldu: google.com/webhp?q=rails+yaml+vulnerability
Teoulas

1
@Teoulas, sana tamamen katılıyorum. Aslında, insanların bunu güvensiz bir şekilde kullanmaması için bir uyarı ekliyorum.
Halil Özgür

16

Bunu halletmenin yerleşik bir yolu yoktur (bunun için actionpack bir yardımcı olabilir). Bunun gibi bir şey tavsiye ederim

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

Yanlış / doğru değişmez değerler yerine 0 ve 0 olmayanların kullanılması da işe yarıyor:

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

3
"!! (s = ~ / regex_here /)" kullanırsanız "s ve ..." korumasına ihtiyacınız yoktur çünkü "nil = ~ / şey /" nil değerini döndürür.
Pavling

Ah gerçekten. Onu ekledim ama eskisini de tuttum, sanırım .matchokumak biraz daha kolay.
Marcel Jackwerth

7

ActiveRecord::Type::Boolean.new.type_cast_from_userbunu Rails'in dahili eşlemelerine göre yapar ConnectionAdapters::Column::TRUE_VALUESve 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

Böylece, aşağıdaki gibi bir başlatıcıda kendi to_b(veya to_boolveya to_boolean) yönteminizi oluşturabilirsiniz:

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

2
Bu, Rails 5'te ActiveRecord :: Type :: Boolean.new.cast (değer) şeklindedir (aşağıdaki CWitty'ye bakın)
Dave Burt


6

Rails 5'te bunu ActiveRecord::Type::Boolean.new.cast(value)bir boolean'a çevirmek için kullanabilirsiniz.


1
ActiveRecord :: Type :: Boolean.new.cast ("42") true döndürür
divideByZero

3

Ruby'de böyle bir şeyin yerleşik olduğunu sanmıyorum. String sınıfını yeniden açabilir ve orada to_bool yöntemini ekleyebilirsiniz:

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

Daha sonra bunu projenizin herhangi bir yerinde şu şekilde kullanabilirsiniz: params[:internal].to_bool


2
Kesinlikle bir to_boolfonksiyon dönüşüne sahip olmak istemem nil; bu yanlış görünüyor. Diğer dönüştürme işlevleri bunu yapmaz: "a".to_idöndürür 0, değilnil
Krease

3

Belki str.to_s.downcase == 'true'tamlık için. strSıfır veya 0 olsa bile hiçbir şey çökemez.


2

Virtus'un kaynak koduna baktığımda, belki şöyle bir şey yapardım:

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

Yalnızca ekleme düşünebiliriz internalonay kutusunun seçili olmadığından ve bunu ekleme yoksa o zaman, doğruysa senin url params[:internal]olacaktır nilRuby false hangi değerlendirir.

Kullandığınız belirli jQuery'ye aşina değilim, ancak istediğinizi aramak için manuel olarak bir URL dizesi oluşturmaktan daha temiz bir yol var mı? Eğer bir göz oldu mu $getve $ajax?


1

To_boolean yöntemine sahip olmak için String sınıfına ekleyebilirsiniz. O zaman 'true' .to_boolean veya '1'.

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

-5

Kimsenin bu basit çözümü göndermemesine şaşırdım. Yani dizeleriniz "doğru" veya "yanlış" olacaksa.

def to_boolean(str)
    eval(str)
end

4
Bu, çünkü Bu çözüm bir güvenlik Felaketi. : D
davidb

1
Bu çözümle ilgili sorun kullanıcı girdisidir - birisi to_boolean("ActiveRecord::Base.connection.execute('DROP TABLE *')")yazarsa, veritabanınızı yok eder (ve doğruya döner!) İyi eğlenceler: D
Ben Aubin

Güzel nokta. İçeriği düşünmüyordum. Uygulanacak en az karakter miktarını düşünüyordum. :)
povess

Bahsedilen güvenlik açığı için kolay bir düzeltme: bool = nil; bool = eval(str) if ["true", "false"].include?(str)Açıklık getirmek için eklemem gerektiğini düşündüm.
Fernando Cordeiro
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.