问题描述
我想在类的属性中使用转换后的名称/值,而不是我们从数据库中获得的。我需要这个的原因是我有两个版本的应用程序指向同一个数据库,但较新的版本最近更新了列名。因此,对于所有使用旧版本的应用,必须使其兼容。
Environment: Rails version: 6.0.3.3 & Ruby version: ruby 2.7.1p83
假设有一个名为 Sprinter 的类。 Sprinter 表看起来像:
id | 名称 | m | s |
---|---|---|---|
1 | 先生。螺栓 | 100 | 9.58 |
Sprinter 实例如下所示:
sprinter = {
"id" => 1,"name" => "Mr. Bolt","m" => 100,"s" => 9.58
}
旧版本需要不同的格式。现在我想要类似的东西:
sprinter = {
"id" => 1,"cm" => 10000,# transformed from `m`
"ms" => 9580 # transformed from `s`
}
m
列名称已转换为 cm
,值也已转换。 s
到 ms
的情况相同。值转换没什么大不了的,但变量名似乎是。
我更喜欢在获取对象时进行内部更新。但是,如果不支持,作为基本级解决方案,我更愿意更改发送给客户端的 json 表示。作为参考,我将其用作嵌套 include
的一部分,例如:
render status: :ok,json: {races: races}.as_json(
{:include => [:sprinters] }
)
谢谢。
解决方法
不用纠结于 .as_json
的内部结构或模型如何进行序列化,您可以使用序列化层来处理模型在 JSON 中的不同表示。
例如,如果您愿意,您可以使用 ActiveModel::Serializers 或 JBuilder,甚至可以自己使用。
module API
module V2
class SprinterAdapter
def intialize(sprinter)
@sprinter = sprinter
end
def to_json
@sprinter.to_json.except("m","s").merge(
"cm" => @sprinter.m * 100,"ms" => @sprinter.s * 1000
)
end
end
end
end
并且在您的控制器中,您将使用序列化程序来呈现资源:
module API
module V2
class SprintersController < ApplicationController
def show
@sprinter = Sprinter.find(params[:id])
render json: SprinterAdapter.new(@sprinter)
end
end
end
end
见:
,您可以通过 Sprinter
中的 select 转换键/值:
Sprinter.select(:id,:name,'m * 100 AS cm','s * 1000 AS ms')
但不确定如何将其与 as_json
结合