Ruby on rails 动态接受任何属性的ActiveModel::Serializer子类?

Ruby on rails 动态接受任何属性的ActiveModel::Serializer子类?,ruby-on-rails,rails-engines,active-model-serializers,modularity,Ruby On Rails,Rails Engines,Active Model Serializers,Modularity,我正在为一个现有的应用程序构建一个API引擎,它将通过ActiveModel::Serializer提供JSON。在现有的应用程序中,有一些控制器只是呈现常规的旧哈希值,这些哈希值不是任何ActiveModel子类的实例——最初,这些都是AJAX端点,所以响应主体是什么类都不重要 我需要在API模块中重新创建一些现有的端点,因此对于这样的实例,我想构建一个自定义序列化程序,它将接受您向它抛出的任何属性。类似于 在控制器中: def show response = { key: "th

我正在为一个现有的应用程序构建一个API引擎,它将通过
ActiveModel::Serializer
提供JSON。在现有的应用程序中,有一些控制器只是呈现常规的旧哈希值,这些哈希值不是任何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
模块Api
模块V1
类CustomSerializer
两个问题:

a) 在控制器中调用render似乎不喜欢我传递给render的args数量,这可能需要
*args
,这表明我编写的重写方法有问题

b) 如果我只是把
attributes*object.class.column\u names.map(&:to\u sym)
放在类的第一行,那么对象在方法之外是未定义的

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

我的问题是:是否有人成功创建了将接受任何属性的序列化程序?我很想知道怎么做


请注意:如果可以的话,我希望通过AMS实现这一点-我们正在为所有响应主体使用JSON API适配器。我宁愿这样做,然后在每次响应不是AM实例时初始化一个与我们使用的json api标准相同的哈希。

对于那些可能遇到相同问题的人,我最终为我想要呈现的任何不是Active Record子类的东西组装了一个catch all序列化程序类。像这样:

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标准,或者为其执行外部api请求并存储在散列中的对象呈现JSON api标准。希望有一天这能帮助别人

对于那些可能偶然发现相同问题的人,我最终为我想要呈现的任何不是Active Record子类的内容组装了一个catch all序列化程序类。像这样:

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标准,或者为其执行外部api请求并存储在散列中的对象呈现JSON api标准。希望有一天这能帮助别人

我必须承认,这是一个有趣的用例——动态构建的属性是否很少?或者更多?作为可以动态返回任何json的API的使用者,我可能很难处理反序列化/解析,并且可能会导致错误。我不知道你的用例,但如果可能的话,我会设计不同的端点来支持不同的用例。我无法提供一个更重要的示例变量,因为我仍在考虑代码库,但关键是,它应该动态映射响应变量中的任何键。在我们的用例中可能会有更多,我只是写了一个真正的小散列作为演示。我必须承认这是一个有趣的用例,只有很少的属性可以动态生成吗?或者更多?作为可以动态返回任何json的API的使用者,我可能很难处理反序列化/解析,并且可能会导致错误。我不知道你的用例,但如果可能的话,我会设计不同的端点来支持不同的用例。我无法提供一个更重要的示例变量,因为我仍在考虑代码库,但关键是,它应该动态映射响应变量中的任何键。在我们的用例中可能还有更多,我只是写了一个真正的小散列作为演示。