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

Ruby FastJsonAPI能否按对象动态设置set_type?适配Rails STI场景

如何在FastJsonAPI中为STI对象单独设置序列化type

嘿,很高兴你觉得FastJsonAPI用着顺手!针对你说的Rails STI场景下给每个对象单独设置type的需求,其实有几种很实用的解决办法,我来给你捋一捋:

方法一:为每个STI子类创建独立序列化器

如果你的STI子类不多,这种方式会比较直观。比如你有Vehicle基类和Car子类:

首先写基础的VehicleSerializer:

class VehicleSerializer
  include FastJsonapi::ObjectSerializer
  attributes :title
end

然后为Car写一个继承自基础序列化器的子类,重写type方法:

class CarSerializer < VehicleSerializer
  def type
    'car'
  end
end

之后在控制器里,根据每个对象的类来匹配对应的序列化器就行:

def index
  vehicles = Vehicle.all
  serialized_data = vehicles.map do |vehicle|
    serializer_class = "#{vehicle.class.name}Serializer".constantize
    serializer_class.new(vehicle).serializable_hash[:data]
  end
  render json: { data: serialized_data }
end

方法二:在基础序列化器中动态设置type(更推荐)

如果子类比较多,一个个写序列化器太麻烦,直接在基础序列化器里根据对象类动态返回type就好。

简单适配类名小写的情况

如果你的type正好是类名的小写单数形式,那一行代码就能搞定:

class VehicleSerializer
  include FastJsonapi::ObjectSerializer
  attributes :title

  def type
    object.class.model_name.singular.downcase
  end
end

这样不管你新增多少STI子类,只要类名和期望的type是对应小写单数关系,就自动适配了。

自定义类名与type的映射

要是类名和type不是简单的大小写对应,比如Truck类要输出heavy_truck这种type,那可以维护一个映射哈希,可读性和扩展性都更好:

class VehicleSerializer
  include FastJsonapi::ObjectSerializer
  attributes :title

  TYPE_MAPPING = {
    Vehicle => 'vehicle',
    Car => 'car',
    Truck => 'heavy_truck'
  }.freeze

  def type
    TYPE_MAPPING[object.class]
  end
end

测试效果

当你序列化混合集合的时候:

vehicles = [Vehicle.create(title: 'Generic Vehicle'), Car.create(title: 'Fast Car')]
render json: VehicleSerializer.new(vehicles).serializable_hash

就能得到你期望的输出:

{ "data": [ { "attributes": { "title": "Generic Vehicle" }, "id": "1", "type": "vehicle" }, { "attributes": { "title": "Fast Car" }, "id": "2", "type": "car" } ] }

这种方式下,FastJsonAPI会自动为集合里的每个对象调用type方法,不用额外处理集合逻辑,非常方便。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:19:29