Я действительно копался в 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. Но Я не хочу использует его как атрибут: я хочу использовать его как внешний 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 или что-то еще. Проблема в том, что я использую такой контроллер, который объединяет несколько типов транспортных средств в методе индекса:
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
@ fongfan999 готово! :) спасибо, что посмотрели.





Это было невозможно в версии 1 FastJsonAPI, которую я использовал для этого. Теперь это возможно начиная с версия 1.2 (хотя я еще не тестировал).
Не могли бы вы привести пример? Насколько я могу судить, до сих пор нет поддержки полиморфизма первого уровня, только отношения.
Возможно, ты прав. Я давно не разбирался в этом и давно не использую Rails. Если вы найдете решение, пингуйте эту ветку, хорошо? Спасибо.
У меня также есть 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
Привет, @allanberry, не могли бы вы показать мне свой
Serializer?