1

我一直在挖掘FastJsonAPI。效果很好。

是否可以基于每个对象设置set_type 序列化程序定义?

即我正在使用Rails STI(单表继承)。我有一组混合的基础对象和派生对象,我希望每个对象都有不同的类型。

这是我想要的 JSON 输出的假示例:

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

当然,我确实有一个type可以使用的对象属性,因为我使用的是 STI。但我不想将其用作属性:我想将其用作 outside type,如上面的 JSON 所示。

序列化器:

class VehicleSerializer
  include FastJsonapi::ObjectSerializer
  set_type :vehicle  # can I tie this to individual objects, right here?
  attributes :title
end

class CarSerializer < VehicleSerializer
  set_type :car
  attributes :title
end

class MotorcycleSerializer < VehicleSerializer
  set_type :motorcycle
  attributes :title
end

class TruckSerializer < VehicleSerializer
  set_type :truck
  attributes :title
end

你看,我有一些控制器只能从单个对象type中提取,对于他们来说,单个对象CarSerializer或其他对象都很好用。问题是当我使用这样的控制器时,它在 index 方法中聚合了多种车辆类型:

require_relative '../serializers/serializers.rb'

class MultiVehiclesController < ApplicationController

  def index
    @vehicles = Vehicle.where(type: ["Car", "Motorcycle"])

    # perhaps there's a way to modify the following line to use a different serializer for each item in the rendered query?
    render json: VehicleSerializer.new(@vehicles).serializable_hash
  end

  def show
    @vehicle = Vehicle.find(params[:id])

    # I suppose here as well:
    render json: VehicleSerializer.new(@vehicle).serializable_hash
  end

end
4

2 回答 2

1

这在我为此使用的 FastJsonAPI 版本 1 中是不可能的。 现在显然可以1.2 版开始(尽管我还没有测试过)。

于 2018-03-21T20:23:19.087 回答
0

我也有 STI,并且想type在渲染不同类的集合时正确使用。我最终得到了一个自定义序列化程序来覆盖hash_for_collection. 在该方法中,可以查找特定的集合项序列化程序并调用其record_hash

这比 fast_jsonapi / jsonapi-serializer 实现慢一点,但现在data集合中的每个项目都有适当的type

class MixedCollectionSerializer < ApplicationSerializer
  include SerializerResolverHelper

  def hash_for_collection
    serializable_hash = {}
    data = []
    included = []
    fieldset = @fieldsets[self.class.record_type.to_sym]
    @resource.each do |record|
      record_klazz = jsonapi_serializer_class_resolver(record,false)
      data << record_klazz.record_hash(record, fieldset, @includes, @params)
      included.concat record_klazz.get_included_records(record, @includes, @known_included_objects, @fieldsets, @params) if @includes.present?
    end
    serializable_hash[:data] = data
    serializable_hash[:included] = included if @includes.present?
    serializable_hash[:meta] = @meta if @meta.present?
    serializable_hash[:links] = @links if @links.present?
    serializable_hash  
  end
end
module SerializerResolverHelper

    def jsonapi_serializer_class_resolver(resource, is_collection)
      if resource.respond_to?(:first)
# if it is a collection and it contailns different types
        first_item_class = resource.first.class
        return MixedCollectionSerializer if resource.any? { |item| item.class != first_item_class }
      end

      JSONAPI::Rails.serializer_class(resource, is_collection)
    rescue NameError
       # if use STI it is necessary to resolve serializers manually
resource = resource.first if is_collection && resource.respond_to?(:first)
      resource_name = case
                      when resource.is_a?(Vehicle) then resource.type.to_s
                      # another STI parent classes ...
                      end

      "#{resource_name}Serializer".constantize if resource_name.present?
    end
end
于 2020-11-29T12:04:53.110 回答