1

我正在使用带有 Rails 的 Postgres。有一个带有子选择的查询,它返回一个布尔值,但 Postgres 总是返回一个类似't'or的字符串'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 trueor THEN 1or 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}
]
4

4 回答 4

4

ActiveRecord 有一个称为ActiveRecord::ConnectionAdapters::Column.value_to_boolean它的方法,它在内部使用将任何类似 true 的值转换为 Rubytrue值。

您可以在代码中使用它。

于 2013-02-17T12:43:19.510 回答
0

当您从 Rails 查询模型时,它的布尔字段会自动转换为 true/false,因为 DB 适配器可以从模式中确定字段的类型。如果您从 db 中选择自定义布尔字段 - 适配器对此一无所知,因此它返回字符串“t”或“f”,您需要手动转换它。

获得预期布尔值的方法之一:

  1. 在 DBMS 端使用提供的 SQL 查询创建视图(例如,参见CREATE VIEW ... PostgreSQL 语句)。视图字段具有类型,因此布尔字段将在您的应用程序中自动转换。假设它叫map_with_measurements.

  2. 创建模型MapWithMeasurement并将其放置在models/map_with_measurement.rb. class MapWithMeasurement < ActiveRecord::Base; end

  3. 使用MapWithMeasurement.find_all.

于 2013-02-17T12:23:23.577 回答
0

你可以使用wannabe_bool gem。 https://github.com/prodis/wannabe_bool

这个 gem 实现了#to_bString、Integer、Symbol 和 NilClass 类的方法。

class Map < ActiveRecord::Base
  def measurements_exist
    self[:measurements_exist].to_b
  end
end
于 2014-10-30T01:21:00.587 回答
0

这是另一个解决方案:

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
于 2016-03-25T21:47:30.717 回答