부울에 문자열 "true"및 "false"


85

Rails 애플리케이션이 있고 jQuery를 사용하여 백그라운드에서 내 검색보기를 쿼리하고 있습니다. 필드 q(검색어) start_date,, end_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

30
아마도 완성도 == '사실'str.downcase
JEMaddux

@AMTourky는 str == 'true' 가 아니어야합니다 || str == '1' 두 개의 "=="?
Pascal

@Lowryder 예! 기본 check_box를 사용하는 경우.
7urkm3n

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

예, 최신 버전입니다!
사티 Kalluri

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 :: Type :: Boolean으로 이동되었습니다.
divideByZero

ActiveModel::Type::Boolean훨씬 더 적합한 경로 인 것 같습니다. ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES"진정한"값 을 포함하고 있지만 이는 우연한 경우 일 뿐이며 특정 사용 사례에 대해서는 진실로 간주되어야하지만 다른 경우에는 포함되지 않는 값이 포함될 수 있다고 주장 할 수 있습니다. 반면 ActiveModel::Type::Boolean에 일반적으로 사용되도록 설계되었습니다.
Lyndsy Simon

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=rails+yaml+vulnerability
Teoulas

1
@Teoulas, 나는 당신과 완전히 동의합니다. 사실, 사람들이 안전하지 않은 방식으로 이것을 사용하지 않도록 알림을 추가하고 있습니다.
Halil Özgür

16

이를 처리하는 기본 제공 방법이 없습니다 (액션 팩에이를위한 도우미가있을 수 있음). 나는 이와 같은 것을 조언 할 것이다

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 /)"를 사용하면 "s and ..."가드가 필요하지 않습니다. "nil = ~ / anything /"은 nil을 반환하기 때문입니다.
Pavling 2011

아 정말. 나는 그것을 추가했지만 .match조금 더 읽기 쉽다고 생각하기 때문에 오래된 것도 유지했습니다 .
Marcel Jackwerth

7

ActiveRecord::Type::Boolean.new.type_cast_from_user레일 '내부 매핑이있어서 수행 ConnectionAdapters::Column::TRUE_VALUESConnectionAdapters::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
그것은 액티브가 :: 레일 (5) 입력 : Boolean.new.cast (값) (아래 CWitty 참조)
데이브 버트


6

Rails 5에서는 ActiveRecord::Type::Boolean.new.cast(value)boolean으로 캐스팅하는 데 사용할 수 있습니다 .


1
하지만 ActiveRecord :: Type :: Boolean.new.cast ( "42")는 true를 반환합니다.
divideByZero

3

루비에는 그런 것이 내장되어 있지 않다고 생각합니다. 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

3

아마도 str.to_s.downcase == 'true'완전성을 위해. 그러면 strnil 또는 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]될 것 nil루비 false로하는 평가됩니다.

나는 당신이 사용하는 특정 jQuery에 익숙하지 않지만 URL 문자열을 수동으로 작성하는 것보다 원하는 것을 호출하는 더 깨끗한 방법이 있습니까? 당신은 한 번 봐 있었나요 $get$ajax?


1

to_boolean 메소드를 갖도록 String 클래스에 추가 할 수 있습니다. 그런 다음 '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
이 솔루션은 보안 Desaster이기 때문입니다. : D
davidb

1
이 솔루션의 문제는 사용자 입력입니다. 누군가를 입력하면 to_boolean("ActiveRecord::Base.connection.execute('DROP TABLE *')")데이터베이스가 파괴되고 true를 반환합니다. D : 재미
벤 오빈

좋은 점. 나는 맥락을 생각하지 않았습니다. 나는 구현할 최소한의 캐릭터를 생각하고 있었다. :)
povess

언급 된 취약점에 대한 쉬운 수정 : bool = nil; bool = eval(str) if ["true", "false"].include?(str)설명을 위해 추가해야한다고 생각했습니다.
Fernando Cordeiro
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.