You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rails中对原生SQL查询结果使用ActiveModelSerializers序列化

原生SQL查询结果使用ActiveModelSerializers序列化的解决方案

问题根因

AMS(ActiveModelSerializers)默认仅支持实现了ActiveModel属性接口的对象序列化,你用到的两种返回值都不符合要求:

  • PG::Result:PostgreSQL驱动返回的原生结果集,仅提供基础的遍历、字段读取方法
  • ActiveRecord::Result:Rails封装的结果集对象,本质是列名+行哈希的组合结构,未实现AMS要求的read_attribute_for_serialization属性读取接口

可行方案

方案1:结果转ActiveModel兼容实例(无对应模型时用)

先把每一行结果转成支持属性访问的对象,推荐两种实现:

  1. 轻量快速实现,用OpenStruct封装:
sql = "SELECT * FROM table"
results = ActiveRecord::Base.connection.exec_query(sql)
# 逐行封装为OpenStruct,支持.访问属性
serializable_records = results.map { |row| OpenStruct.new(row) }
options = { each_serializer: MySerializer }
output = ActiveModelSerializers::SerializableResource.new(serializable_records, options).as_json
  1. 自定义ActiveModel类(需要扩展方法、性能要求高时用):
# 自定义轻量模型类
class SqlQueryResult
  include ActiveModel::Model
  # 动态绑定所有查询列的访问权限,也可以手动指定attr_accessor :id, :col1...
  attr_accessor(*ActiveRecord::Base.connection.exec_query("SELECT * FROM table LIMIT 0").columns)
end

# 调用时直接实例化
serializable_records = results.map { |row| SqlQueryResult.new(row) }

方案2:用find_by_sql查询(查询内容有对应ActiveRecord模型时用)

如果你的SQL查询的表已经有对应的ActiveRecord模型,直接用模型的find_by_sql方法,返回的结果就是模型实例,天生支持AMS序列化:

# 假设table对应的模型为Table
results = Table.find_by_sql("SELECT * FROM table")
options = { each_serializer: MySerializer }
output = ActiveModelSerializers::SerializableResource.new(results, options).as_json

注:该方法即使SQL只查询部分字段也可正常运行,AMS只会读取序列化器中声明的字段,不会触发额外查询。

内容的提问来源于stack exchange,提问作者ninja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 22:24:06