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

时间:2019-02-14 01:01:23

标签: ruby-on-rails rails-engines active-model-serializers modularity

我正在为现有应用构建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

问题对:

a)控制器中对render的调用似乎不喜欢我传递给render的args的数量,该数量应该花费*args,这对我来说意味着重写方法有问题我写过

b)如果我只是将attributes *object.class.column_names.map(&:to_sym)放在类的第一行中,则在方法外部未定义对象。

c)我在一个方法内部调用它,结果哈希嵌套在我选择调用该方法的任何内部。真的不是我的想法。

我的问题:是否有人成功创建了可以接受任何属性的序列化程序?很想知道如何。

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

1 个答案:

答案 0 :(得分:0)

对于那些可能偶然发现同一问题的人,我最终为我想呈现的,不是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

基本上只是意味着我仍然可以为仅作为Hash类实例的任何内容或我正在对其进行外部API请求并将其存储在Hash中的任何内容呈现JSON api标准。希望有一天能对某人有所帮助。