需要将Postgres(== String)中的布尔值转换为Ruby布尔值
我正在使用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} ]
ActiveRecord有一个名为ActiveRecord::ConnectionAdapters::Column.value_to_boolean
它在内部使用它将任何类似true的值转换为Ruby true
值。
您可以在代码中使用它。
当您从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
。
你可以使用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
这是另一个解决方案:
boolean = (value_from_postgres =~ /^t$/i) == 0
将’t’的value_from_postgres转换为布尔值true或将’f’转换为布尔值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
如果您期望字符串“true”或“false”,则可以修改此行中的常规表达式以匹配/ ^ true $ / i。 这比使用三元组或gem更灵活,因为您可以编写它以将匹配转换为任何正则表达式为布尔值true。
使用三元组看起来像:
boolean = value_from_postgres.eql?('t') ? true : false
- 你已经拿破了包 – Postgres gem for rails
- 在postgresql中,“数据库”和“关系”有什么区别? (’错误关系x不存在’,’错误数据库x已存在’)
- 用点击将SQLite数据库推送到Heroku?
- Rails Postgres架构问题 – 以下架构之一无效:“test”“public”
- 函数使用Postgres数据库绘制错误,但不在Sqlite上绘制
- 试图为ror app设置postgres,收到错误 – fe_sendauth:没有提供密码
- ActiveRecord中的PostgreSQL jsonb字段属于关联
- 为什么我的Rails 4 / Postgres中的所有表都以1的“维度”创建?
- 错误:缺少表“self”的FROM子句条目(Rails 4 Active Record事务,postgresql 9.4))