Как отправить логический параметр в Rails?

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

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

@show_all = params[:show_all]

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

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

Ответ 1

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

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

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

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

Ответ 2

UPDATE: Rails 5:

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

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

Ответ 3

Этот вопрос довольно старый, но так как я пару раз сталкивался с этой проблемой и мне не нравилось предлагаемое решение, я сам что-то взломал, что позволяет использовать несколько строк для истины например, "да", 'on', 't' и наоборот для false.

Обезьяна патёт класс String и добавьте метод для преобразования их в boolean и поместите этот файл в /config/initializers, как предлагается здесь: Патч обезьяны в 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?

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

Ответ 4

@show_all = params[:show_all] == "1" ? true : false

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

ИЗМЕНИТЬ

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

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

Ответ 5

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

@show_all == "true"

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

Ответ 6

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

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

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

Ответ 7

Вы можете преобразовать все ваши логические параметры в реальные булевы, как это:

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

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

Ответ 8

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

Рассмотрим следующее: По представлению индекса моей продукции по умолчанию я хочу показать только ограниченный набор продуктов (например, те, которые находятся на складе). То есть, если я хочу вернуть все продукты, я могу отправить 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

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

Ответ 9

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

def show_all= value
  @show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end