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
相关产品推荐
相关产品推荐

