Rails 从数据库转换变量名和值

问题描述

我想在类的属性中使用转换后的名称/值,而不是我们从数据库中获得的。我需要这个的原因是我有两个版本的应用程序指向同一个数据库,但较新的版本最近更新了列名。因此,对于所有使用旧版本的应用,必须使其兼容。

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,值也已转换。 sms 的情况相同。值转换没什么大不了的,但变量名似乎是。

我更喜欢在获取对象时进行内部更新。但是,如果不支持,作为基本级解决方案,我更愿意更改发送给客户端的 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

结合