Ответ 1
Насколько я знаю, нет встроенного способа литья строк для булевых элементов,
но если ваши строки состоят только из 'true'
и 'false'
, вы можете сократить свой метод до следующего:
def to_boolean(str)
str == 'true'
end
У меня есть приложение 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
Но я думаю, что должен быть более рубинский способ справиться с этой проблемой! Разве нет...?
Насколько я знаю, нет встроенного способа литья строк для булевых элементов,
но если ваши строки состоят только из 'true'
и 'false'
, вы можете сократить свой метод до следующего:
def to_boolean(str)
str == 'true'
end
ActiveRecord обеспечивает чистый способ сделать это.
def is_true?(string)
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(string)
end
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
имеет все очевидные представления значений True как строки.
Обратите внимание, что этот ответ в его голой форме подходит только для другого варианта использования, указанного ниже, а не для ответа на вопрос. Несмотря на то что в основном исправлено, были многочисленные уязвимости связанные с 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 файлов.
Нет никакого встроенного способа справиться с этим (хотя у 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
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
Вы можете использовать жемчужину wannabe_bool. https://github.com/prodis/wannabe_bool
Этот драгоценный камень реализует метод #to_b
для классов String, Integer, Symbol и NilClass.
params[:internal].to_b
В Rails 5 вы можете использовать ActiveRecord::Type::Boolean.new.cast(value)
для перевода его в логическое.
Я не думаю, что в 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
Глядя на исходный код 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
Возможно, str.to_s.downcase == 'true'
для полноты. Тогда ничто не может сбой, даже если str
равно nil или 0.
Вы можете рассматривать только добавление internal
к вашему URL-адресу, если оно истинно, тогда, если флажок не установлен, и вы не добавляете его, params[:internal]
будет nil
, который вычисляет значение false в Ruby.
Я не знаком с конкретным jQuery, который вы используете, но есть ли более чистый способ вызвать то, что вы хотите, чем вручную создать строку URL? Вы видели $get
и $ajax
?
Вы можете добавить к классу String метод to_boolean. Тогда вы можете сделать "true".to_boolean или "1".to_boolean
class String
def to_boolean
self == 'true' || self == '1'
end
end
Я удивлен, что никто не опубликовал это простое решение. То есть, если ваши строки будут "истинными" или "ложными".
def to_boolean(str)
eval(str)
end