如何在Rails中提交布尔参数?


75

我正在提交show_all带有值的参数true。该值与模型无关。

我的控制器正在将此参数分配给实例变量:

@show_all = params[:show_all]

但是,@show_all.is_a? String并且if @show_all == true总是失败。

Rails将哪些值解析为布尔值?如何明确指定我的参数是布尔值而不是字符串?


有没有这样的事情在红宝石布尔值,仅TrueClassFalseClass
NullUserException

4
当参数与模型关联时,Rails仍会自动对其进行计算-如果数据库中的列类型为布尔值,则将参数视为aTrueClassFalseClass。知道我如何才能做到这一点吗?
nfm 2010年

如何检查参数为真或假的可能重复项因为“是否存在更好的方法来基于参数为真或假来执行if / else语句?”
Ciro Santilli郝海东冠状病六四事件法轮功

这个问题的一个好的解决方案也可能是这个问题的一个好的解决方案。
Ciro Santilli郝海东冠状病六四事件法轮功2014年

Answers:


70

我想对zetetic答案发表评论,但由于目前还无法完成,我将其发布为答案。

如果您使用

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

那么您可以删除,? true : false因为params[:show_all] == "1"语句本身将评估为true或false,因此不需要三元运算符。


对于将来的参考,这是最干净的答案。从技术上讲,布尔值可以作为“ true”或“ false”传递,但传递数字更好,因为它可以防止诸如“ true” ==“ True”之类的简单错误返回false。是1或0
sybohy

100

更新:Rails 5:

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

更新:Rails 4.2为此提供了公共API:

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

上一个答案:

ActiveRecord在https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/column.rb中维护true / false表示形式的列表

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

这不是Rails的公共API的一部分,因此我将其包装到一个辅助方法中:

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
我们应该注意,但是ActiveRecord::Type::Boolean.new.type_cast_from_user("0")返回的结果false与您提到的一样,但是在Rails 5中它将开始返回true:DEPRECATION警告:您试图分配的值不是显式的,true也不false是布尔值。目前,此值转换为false。这将进行更改以匹配Ruby的语义,并将true在Rails 5中强制转换为。如果您希望保持当前行为,则应显式处理要转换为的值false
约翰·史密斯,

1
ActiveRecord::Type::Boolean只是的别名ActiveModel::Type::Boolean。使用原始类可能要好一点。
Tim Dorr

22

这个问题比较老,但是由于我遇到过几次这个问题,并且不喜欢提出的任何解决方案,所以我自己修改了一些东西,允许使用多个字符串表示“ true ”,例如“ yes”,“ on” ,“ t”,反之则为false。

Monkey修补了String类,并添加了一种将其转换为boolean的方法,然后/config/initializers按照此处的建议将其放入:Rails 3中的Monkey Patching

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?

它非常整洁,有助于保持控制器/模型的清洁。


2
一个出色的解决方案,干净整洁,并为String类添加了真正有用的功能。非常好。
肖恩·卡梅伦

19
恭喜,您现在String#to_bool可以返回nil。请对此进行一段时间的沉思,然后将方法重命名为String#maybe_bool?或诉诸ArgumentError
Nicos 2013年

2
这可以进一步简化为def to_bool; ['true', '1', 'yes', 'on', 't'].include? self; end
lobati

5
每次调用此方法时,都会生成至少一个数组。将这些数组移到冻结的常量中。TRUE_VALUES = ['true'.freeze, '1'.freeze, 'yes'.freeze, 'on'.freeze, 't'.freeze]。这a)节省了内存,b)防止了字符串的运行时更改。
克里斯(Chris)

@Nicos在我同意您的意见的同时,请记住,至少在Rails 3.2(尚未在其他版本中进行测试)中,ActiveRecord::ConnectionAdapters::Column.value_to_boolean('')它将返回nil
亚历山大

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

如果您要从复选框传递值,则此方法应该很好用-哈希中缺少键会生成nil,在条件条件下其结果为false。

编辑

正如指出的在这里,三元运算符是没有必要的,所以这可能仅仅是:

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


4

您可以将相等性声明更改为:

@show_all == "true"

如果希望它是布尔值,则可以在字符串类上创建一个方法以将字符串转换为布尔值。


3

我认为最简单的解决方案是针对其字符串表示形式测试“布尔”参数。

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

不管Rails提供的参数为字符串“ true”还是“ false”,还是实际的TrueClass或FalseClass,此测试始终有效。


1

另一种方法是只传递没有值的密钥。虽然使用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

如果键存在于params中,那么无论其值如何,我都会知道我需要返回所有产品,而无需键入值。


我决定在自己的用例中使用这种方法。过去,我一直对此持怀疑态度,但是如果没有真正的用例来说明虚假值,那么以这种方式来做就很有意义了!
RSmithlal

1

您可以将以下内容添加到模型中:

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

1

你可以做

@show_all = params[:show_all].downcase == 'true'

0

您可以像这样将所有布尔参数转换为真实的布尔值:

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

在此解决方案中,nil参数将变​​为false。


0

值得注意的是,如果您要在Rails> 5.2中将值传递给ActiveModel,更简单的解决方案是使用attribute

class Model
  include ActiveModel::Attributes

  attribute :show_all, :boolean
end

Model.new(show_all: '0').show_all # => false

这里可以看出。


在5.2之前,我使用:

class Model
  include ActiveModel::Attributes

  attribute_reader :show_all

  def show_all=(value)
    @show_all = ActiveModel::Type::Boolean.new.cast(value)
  end
end

Model.new(show_all: '0').show_all # => false
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.