我提交的参数show_all
的值为true
。该值与模型无关。
我的控制器将此参数分配给实例变量:
@show_all = params[:show_all]
但是,@show_all.is_a? String
和if @show_all == true
始终失败。
Rails解析为布尔值的值是什么?如何明确指定我的参数是布尔值,而不是字符串?
答案 0 :(得分:87)
更新: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
中维护一个真/假的表示列表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
答案 1 :(得分:67)
我想对zetetic回答发表评论,但由于我不能这样做,我会发布这个作为答案。
如果您使用
@show_all = params[:show_all] == "1"
然后您可以删除? true : false
,因为params[:show_all] == "1"
语句本身将评估为true或false,因此不需要三元运算符。
答案 2 :(得分:21)
这个问题相当陈旧,但由于我偶然遇到过这个问题,而且并不喜欢任何提出的解决方案,我自己攻击了一些允许使用多个字符串 true < / strong>例如&#39; yes&#39;,&#39; on&#39;,&#39; t&#39;与错误相反。
Monkey修补类String,并添加一个方法将它们转换为boolean,并按照此处的建议将此文件放在/config/initializers
中:Monkey Patching in 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?
它非常整洁,有助于保持控制器/模型的清洁。
答案 3 :(得分:17)
@show_all = params[:show_all] == "1" ? true : false
如果您从复选框传递值,这应该可以正常工作 - 哈希中缺少的键生成nil,在条件中计算结果为false。
修改强>
正如here指出的那样,三元运算符不是必需的,所以这可以是:
@show_all = params[:show_all] == "1"
答案 4 :(得分:4)
您可以将等式声明更改为:
@show_all == "true"
如果您希望它是一个布尔值,您可以在字符串类上创建一个方法,将字符串转换为布尔值。
答案 5 :(得分:3)
我认为最简单的解决方案是针对其String表示测试“boolean”参数。
@show_all = params[:show_all]
if @show_all.to_s == "true"
# do stuff
end
无论Rails是以字符串“true”还是“false”或实际TrueClass或FalseClass的形式提供参数,此测试都将始终有效。
答案 6 :(得分:1)
你可以做
@show_all = params[:show_all].downcase == 'true'
答案 7 :(得分:0)
您可以将所有布尔参数转换为真正的布尔值,如下所示:
%w(show_all, show_featured).each do |bool_param|
params[bool_param.to_sym] = params[bool_param.to_sym] == "true"
end
在此解决方案中,nil参数将变为false。
答案 8 :(得分:0)
另一种方法是仅传递没有值的键。尽管使用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中,那么无论其值如何,我都知道我需要返回所有产品,而不需要强制转换值。
答案 9 :(得分:0)
您可以将以下内容添加到模型中:
def show_all= value
@show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
答案 10 :(得分:0)
值得注意的是,如果要在Rails> 5.2中将值传递给 ActiveModel ,更简单的解决方案是使用attribute
class Model
include ActiveModel::Attributes
attribute :show_all, :boolean
end
Model.new(show_all: '0').show_all # => false
可以看到here。
在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
答案 11 :(得分:0)
虽然没有明确问题是关于什么的,但我觉得这是适当的相关;如果您尝试在 rails 测试中传递真正的布尔变量,那么您将需要以下语法。
post :update, params: { id: user.id }, body: { attribute: true }.to_json, as: :json
我来到这个线程就是为了寻找这个语法,所以我希望它也能帮助那些寻找这个的人。归功于Lukom