Строка "true" и "false" для boolean

У меня есть приложение 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", и мне нужно отбросить ее в boolean. Конечно, я могу сделать это вот так:

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

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

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

Обратите внимание, что этот ответ в его голой форме подходит только для другого варианта использования, указанного ниже, а не для ответа на вопрос. Несмотря на то что в основном исправлено, были многочисленные уязвимости связанные с YAML-уязвимостью, которые были вызваны загрузкой пользовательского ввода в виде YAML.


Трюк, который я использую для преобразования строк в bools, YAML.load, например:

YAML.load(var) # -> true/false if it 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 vars являются строками один раз внутри кода, значение config.etc.something будет строкой "false", и оно будет неправильно оценивать до true. Но если вы сделаете так:

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

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

Ответ 4

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

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

Ответ 5

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 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 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

Ответ 6

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

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

params[:internal].to_b

Ответ 7

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

Ответ 11

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

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

Ответ 12

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

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

Ответ 13

Я удивлен, что никто не опубликовал это простое решение. То есть, если ваши строки будут "истинными" или "ложными".

def to_boolean(str)
    eval(str)
end