it-swarm.com.ru

Строка "true" и "false" для логического значения

У меня есть приложение Rails, и я использую jQuery для запроса моего вида поиска в фоновом режиме. Существуют поля q (поисковый запрос), start_date, end_date и internal. Поле 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

Но я думаю, что должен быть более рубиновый способ решения этой проблемы! Разве нет ...?

82
davidb

Насколько я знаю, не существует встроенного способа приведения строк к логическим значениям, но если ваши строки состоят только из 'true' и 'false', вы можете сократить свой метод до следующего:

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

ActiveRecord обеспечивает чистый способ сделать это.

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

ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES имеет все очевидные представления значений True в виде строк.

47
Satya Kalluri

Уведомление о безопасности

Обратите внимание, что этот ответ в чистом виде подходит только для другого варианта использования, указанного ниже, а не для вопроса в вопросе. Хотя в основном это исправлено, было множество уязвимостей, связанных с 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

Теперь, поскольку переменные ENV являются строками внутри кода, значением config.etc.something будет строка "false", и она будет неверно оценена как true. Но если вы делаете так:

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

было бы все хорошо. Это также совместимо с загрузкой конфигов из файлов .yml.

23
Halil Özgür

Нет никакого встроенного способа справиться с этим (хотя у 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

Что также работает, так это использование 0 и не 0 вместо литералов false/true:

def to_boolean(s)
  !s.to_i.zero?
end
16
Marcel Jackwerth

ActiveRecord::Type::Boolean.new.type_cast_from_user делает это в соответствии с внутренними отображениями Rails 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
7
AlexChaffee

В Rails 5 вы можете использовать ActiveRecord::Type::Boolean.new.cast(value) для приведения его к логическому значению.

5
CWitty

Вы можете использовать камень wannabe_bool. https://github.com/prodis/wannabe_bool

Этот гем реализует метод #to_b для классов String, Integer, Symbol и NilClass.

params[:internal].to_b
5
Prodis

Я не думаю, что что-то подобное встроено в 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

3
socha23

Возможно str.to_s.downcase == 'true' для полноты. Тогда ничто не может дать сбой, даже если str равно nil или 0.

3
user1839842

Глядя на исходный код 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
2
d11wtq

Вы можете добавить в класс String метод to_boolean. Тогда вы могли бы сделать 'true'.to_boolean или' 1'.to_boolean

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

Вы могли бы рассмотреть только добавление internal к вашему URL, если оно истинно, тогда, если флажок не установлен и вы не добавляете его, params[:internal] будет nil, что оценивается как ложное в Ruby.

Я не настолько знаком с конкретным jQuery, который вы используете, но есть ли более чистый способ вызова того, что вы хотите, чем создание строки URL-адреса вручную? Вы смотрели на $get и $ajax?

1
Russell