Как мне передать логический параметр в Rails? - PullRequest
66 голосов
/ 09 сентября 2010

Я отправляю параметр show_all со значением true. Это значение не связано с моделью.

Мой контроллер назначает этот параметр переменной экземпляра:

@show_all = params[:show_all]

Однако @show_all.is_a? String и if @show_all == true всегда терпят неудачу.

Какие значения Rails анализирует как логические значения? Как я могу явно указать, что мой параметр логический, а не строка?

Ответы [ 9 ]

88 голосов
/ 17 октября 2013

ОБНОВЛЕНИЕ: Rails 5:

ActiveRecord::Type::Boolean.new.deserialize('0')

ОБНОВЛЕНИЕ: Rails 4.2 имеет публичный API для этого:

ActiveRecord::Type::Boolean.new.type_cast_from_user("0") # false

ПРЕДЫДУЩИЙ ОТВЕТ:

ActiveRecord поддерживает список представлений для true / false в https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/column.rb

2.0.0-p247 :005 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean("ON")
2.0.0-p247 :006 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean("F")

Это не часть публичного API Rails, поэтому я обернул его во вспомогательный метод:

class ApplicationController < ActionController::Base
  private

  def parse_boolean(value)
    ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
  end
end

и добавлен базовый тест:

class ApplicationControllerTest < ActionController::TestCase
  test "parses boolean params" do
    refute ApplicationController.new.send(:parse_boolean, "OFF")
    assert ApplicationController.new.send(:parse_boolean, "T")
  end
end
67 голосов
/ 09 сентября 2010

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

Если вы используете

@show_all = params[:show_all] == "1"

тогда вы можете отбросить ? true : false, потому что сам оператор params[:show_all] == "1" будет иметь значение true или false и, следовательно, троичный оператор не нужен.

21 голосов
/ 31 декабря 2012

Этот вопрос довольно старый, но так как я сталкивался с этой проблемой пару раз и мне не понравилось ни одно из предложенных решений, я сам взломал что-то, что позволяет использовать несколько строк для true такие как «да», «вкл», «т» и наоборот для ложного.

Обезьяна исправит класс String, добавит метод для преобразования их в логическое значение и поместит этот файл в /config/initializers, как предлагается здесь: Patching Monkey в Rails 3

class String
  def to_bool
    return true if ['true', '1', 'yes', 'on', 't'].include? self
    return false if ['false', '0', 'no', 'off', 'f'].include? self
    return nil
  end
end

Обратите внимание, что если значение не является ни одним из допустимых значений true или false, оно возвращает nil. Это не то же самое для поиска ?paid=false (вернуть все неоплаченные записи), чем ?paid= (я не уточняю, должен ли он быть оплачен или нет - поэтому откажитесь от этого).

Тогда, следуя этому примеру, логика в вашем контроллере будет выглядеть так:

Something.where(:paid => params[:paid].to_bool) unless params[:paid].try(:to_bool).nil?

Это довольно аккуратно, и помогает содержать контроллеры / модели в чистоте.

17 голосов
/ 09 сентября 2010
@show_all = params[:show_all] == "1" ? true : false

Это должно хорошо работать, если вы передаете значение из флажка - отсутствующий ключ в хэше генерирует nil, что в условном выражении равно false.

Как указано здесь , троичный оператор не требуется, поэтому это может быть просто:

@show_all = params[:show_all] == "1"

4 голосов
/ 09 сентября 2010

Вы можете изменить свой оператор равенства на:

@show_all == "true"

Если вы хотите, чтобы он был логическим, вы можете создать метод в строковом классе для преобразования строки в логическое значение.

3 голосов
/ 06 января 2014

Я думаю, что самое простое решение - это проверить "логические" параметры по отношению к их строковому представлению.

@show_all = params[:show_all]
if @show_all.to_s == "true"
   # do stuff
end

Независимо от того, передает ли Rails параметр в виде String "true" или "false" или в качестве фактического TrueClass или FalseClass, этот тест всегда будет работать.

0 голосов
/ 12 августа 2016

Вы можете добавить следующее к вашей модели:

def show_all= value
  @show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
0 голосов
/ 08 июня 2016

Другой подход - передавать только ключ без значения. Хотя использование ActiveRecord::Type::Boolean.new.type_cast_from_user(value) довольно удобно, может возникнуть ситуация, когда присвоение значения ключу param является излишним.

Примите во внимание следующее: В моем представлении индекса товаров по умолчанию я хочу показать только коллекцию товаров в определенном объеме (например, те, которые есть в наличии). То есть, если я хочу вернуть все продукты, я могу отправить myapp.com/products?show_all=true и ввести параметр show_all для логического значения.

Однако обратный вариант - myapp.com/products?show_all=false просто не имеет смысла, так как он вернет тот же набор продуктов, что и myapp.com/products.

Альтернатива:

если я хочу вернуть всю коллекцию с незаданной областью, тогда я отправляю myapp.com/products?all и в моем контроллере определяю

private

def show_all?
  params.key?(:all)
end

Если ключ присутствует в параметрах, то, независимо от его значения, я буду знать, что мне нужно вернуть все продукты, не нужно указывать значение типа.

0 голосов
/ 16 августа 2012

Вы можете преобразовать все свои логические параметры в настоящие логические значения следующим образом:

%w(show_all, show_featured).each do |bool_param|
  params[bool_param.to_sym] = params[bool_param.to_sym] == "true"
end

В этом решении nil-параметры станут ложными.

...