ActiveModel::Serializer 将动态接受任何属性的子类?

ActiveModel::Serializer Subclass that will accept any attribute dynamically?

我正在为现有应用构建一个 API 引擎,它将为 JSON 和 ActiveModel::Serializer 提供服务。在现有的应用程序上,有一些控制器只呈现不是任何 ActiveModel subclass 实例的常规旧散列 - 最初,这些是 AJAX 端点所以 class 响应 body 是。

我需要在 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

几个问题:

a) 在控制器中对渲染的调用似乎不喜欢我传递给渲染的参数数量,据推测这需要 *args,这表明我的覆盖我写的方法。

b) 如果我只是将 attributes *object.class.column_names.map(&:to_sym) 放在 class 的第一行,那么 object 在方法之外是未定义的。

c) 我在一个方法中调用它,生成的散列嵌套在我选择调用该方法的任何内容中。不是我想的那样。

我的问题:有没有人成功创建了一个可以接受任何属性的序列化程序?很想知道怎么做。

请注意: 如果可以的话,我想用 AMS 实现这一点 - 我们正在使用 JSON API 的适配器来进行所有响应身体。我宁愿让这项工作正常进行,然后初始化一个与我们每次响应不是 AM 实例时使用的 json api 标准相同的散列。

对于可能偶然发现相同问题的人,我最终组装了一个包罗万象的序列化程序 class 用于任何我想呈现的不是 Active 的子 class 的东西记录。像这样:

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

基本上只是意味着我仍然可以为任何只是散列 class 实例的任何东西或我正在为其做外部 JSON api 的任何东西呈现标准 API 请求并存储在哈希中。希望有一天这对某人有所帮助。