Ruby FastJsonAPI dynamic set_type?

Я действительно копался в 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

Привет, @allanberry, не могли бы вы показать мне свой Serializer?

fongfan999 17.03.2018 07:39

@ fongfan999 готово! :) спасибо, что посмотрели.

aljabear 17.03.2018 14:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
1 126
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это было невозможно в версии 1 FastJsonAPI, которую я использовал для этого. Теперь это возможно начиная с версия 1.2 (хотя я еще не тестировал).

Не могли бы вы привести пример? Насколько я могу судить, до сих пор нет поддержки полиморфизма первого уровня, только отношения.

thisismydesign 04.03.2019 13:12

Возможно, ты прав. Я давно не разбирался в этом и давно не использую Rails. Если вы найдете решение, пингуйте эту ветку, хорошо? Спасибо.

aljabear 04.03.2019 23:29

У меня также есть 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

Другие вопросы по теме