我正在使用Postgres和Rails。有一个带有subselect的查询返回一个布尔值,但Postgres总是返回一个像't'
或'f'
这样的字符串。但是在生成的JSON中我需要一个真正的布尔值。
这是我的疑问:
SELECT
*,
EXISTS (
SELECT TRUE
FROM measurement
JOIN experiment ON measurement.experiment_id = experiment.id
JOIN location ON experiment.location_id = location.id
WHERE location.map_id = map.id
LIMIT 1
) AS measurements_exist
FROM "map"
无论我使用THEN true
还是THEN 1
还是THEN 'true'
,我都会得到一个字符串。所以我的JSON响应总是这样:
[
{"id":8, ..., "measurements_exist":"f"},
{"id":9, ..., "measurements_exist":"t"}
]
但它应该(!)看起来像那样:
[
{"id":8, ..., "measurements_exist":false},
{"id":9, ..., "measurements_exist":true}
]
有没有办法让这个工作正常?
谢谢!
只需为相应的模型(此处为Map
)提供属性访问器,即使用value_as_boolean
转换值。因此,每次控制器尝试访问该值时,它都会自动使用属性访问器方法。
控制器代码:
class MapsController < ApplicationController
def index
select = ["*"]
select.push(measurements_exist) # This will just insert the string returned by the 'measurements_exist' method
maps = Map.select(select) # Results in 'SELECT *, EXISTS (...) AS measurements_exist FROM "map"'
render json: maps
end
private
def measurements_exist
"EXISTS (
SELECT TRUE
FROM measurement
JOIN experiment ON measurement.experiment_id = experiment.id
JOIN location ON experiment.location_id = location.id
WHERE location.map_id = map.id
LIMIT 1
) AS measurements_exist"
end
end
型号代码:
class Map < ActiveRecord::Base
def measurements_exist
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(self[:measurements_exist])
end
end
结果JSON:
[
{"id":7, ..., "measurements_exist":false},
{"id":6, ..., "measurements_exist":true}
]
答案 0 :(得分:4)
ActiveRecord有一个名为ActiveRecord::ConnectionAdapters::Column.value_to_boolean
的方法,它在内部用于将任何类似true的值转换为Ruby true
值。
您可以在代码中使用它。
答案 1 :(得分:0)
当您从Rails查询模型时,其布尔字段会自动转换为true / false,因为DB适配器可以确定模式中的字段类型。如果从db中选择自定义布尔字段 - 适配器对它没有任何了解,那么它返回字符串't'或'f',您需要手动转换它。
获得预期布尔值的方法之一:
在DBMS端使用提供的SQL查询创建视图(例如,参见PostgreSQL的CREATE VIEW ...语句)。视图字段具有类型,因此布尔字段将自动在您的应用中转换。假设它叫map_with_measurements
。
创建模型MapWithMeasurement
并将其放在models/map_with_measurement.rb
中。
class MapWithMeasurement < ActiveRecord::Base; end
使用MapWithMeasurement.find_all
。
答案 2 :(得分:0)
你可以使用wannabe_bool gem。 https://github.com/prodis/wannabe_bool
这个gem为String,Integer,Symbol和NilClass类实现了一个#to_b
方法。
class Map < ActiveRecord::Base
def measurements_exist
self[:measurements_exist].to_b
end
end
答案 3 :(得分:0)
这是另一种解决方案:
boolean = (value_from_postgres =~ /^t$/i) == 0
将value_from_postgres转换为&#39; t&#39;布尔值为真或者&#39; f&#39; to boolean false
$irb
2.2.1 :001 > value_from_postgres = 't'
=> "t"
2.2.1 :002 > (value_from_postgres =~ /^t$/i) == 0
=> true
2.2.1 :003 > value_from_postgres = 'f'
=> "f"
2.2.1 :004 > (value_from_postgres =~ /^t$/i) == 0
=> false
如果你期望一个字符串&#34; true&#34;可以修改此行中的常规表达式以匹配/ ^ true $ / i。或&#34;假&#34;。这比使用三元组或gem更灵活,因为您可以编写它以将匹配转换为任何正则表达式为布尔值true。
使用三元组看起来像:
boolean = value_from_postgres.eql?('t') ? true : false