ActiveModel :: Serializer Подкласс, который будет принимать любой атрибут динамически? - PullRequest
0 голосов
/ 14 февраля 2019

Я создаю движок API для существующего приложения, который будет обслуживать JSON с ActiveModel::Serializer.В существующем приложении есть некоторые контроллеры, которые просто воспроизводят обычные старые хэши, которые не являются экземплярами какого-либо подкласса ActiveModel - изначально это были конечные точки AJAX, поэтому не имело значения, к какому классу относится тело ответа.

Мне нужно воссоздать некоторые из этих существующих конечных точек в модуле API, поэтому для подобных случаев я хочу создать собственный сериализатор, который будет принимать любые атрибуты, которые вы к нему добавляете.что-то вроде ...

В контроллере:

def show
  response = {
    key: "this is a custom object and not an AM instance"
  }
  render json: response, serializer: Api::V1::CustomSerializer
end

И сериализатора:

module Api
  module V1
    class CustomSerializer < ActiveModel::Serializer

      def attributes
        *object.keys.map(&:to_sym)
      end

      def read_attribute_for_serialization(attr)
        object[attr.to_s]
      end


    end
  end
end

Пара проблем:

а)call для рендеринга в контроллере не похоже на количество аргументов, которые я передал для рендеринга, что предположительно занимает *args, что говорит о том, что что-то не так с методами переопределения, которые я написал.

b) Если бы я просто поместил attributes *object.class.column_names.map(&:to_sym) в первой строке класса, объект не определен вне метода.

в) Я вызываю его внутри метода, результирующий хэш вложен во все, что я выбрал для вызова этого метода.Не совсем то, что я имел в виду.

Мой вопрос: кто-нибудь успешно создал сериализатор, который будет принимать любой атрибут?Хотелось бы узнать, как это сделать.

ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ: Я бы хотел добиться этого с помощью AMS, если смогу - мы используем адаптер для JSON API для всех наших тел ответов.Я бы предпочел сделать эту работу, а затем инициализировать хеш, идентичный стандарту json api, который мы используем каждый раз, когда ответ не является экземпляром AM.

1 Ответ

0 голосов
/ 18 марта 2019

Для людей, которые могли столкнуться с той же проблемой, я закончил собирать универсальный класс сериализатора для всего, что я хочу визуализировать, но это не подкласс Active Record.Вот так:

module Api
  module V1
    class CustomSerializer

      def initialize(obj, error: false, type: nil)
        @hash = error ? error_hash(obj) : success_hash(type, obj)
      end

      def to_h
        @hash
      end

      private

      def error_hash(obj)
        {
          errors: {
            pointer: obj[:error] || obj[:errors]
          },
          detail: detail(obj)
        }
      end

      def success_hash(type, obj)
        {
          id: obj.try(:id) ? obj[:id] : nil,
          type: type.nil? ? 'hash' : type,
          data: obj.try(:id) ? obj.except(:id) : obj,
          links: ''
        }
      end

      def detail(obj)
        obj[:detail] || obj[:message] || obj[:msg]
      end


    end
  end
end

Обратите внимание, что я работаю со стандартом JSON API.Затем, вместо того, чтобы делать что-то подобное для сериализатора activemodel:

render json: @device, serializer: Api::V1::DeviceSerializer

Я могу сделать что-то вроде этого:

render json: Api::V1::CustomSerializer.new(@response, error: false, type: 'feed').to_h

в основном просто означает, что я все еще могу сделать стандарт JSON API длявсе, что является просто экземпляром класса Hash, или что-то, для чего я делаю внешние запросы API и храню в Hash.Надеюсь, это поможет кому-нибудь когда-нибудь.

...