我正在为现有应用程序构建一个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似乎并不喜欢我传递给渲染的args数量,这可能需要使用*args
,这表明我写的覆盖方法有问题。
b)如果我只是将attributes *object.class.column_names.map(&:to_sym)
放在类的第一行,则对象在方法之外是未定义的。
c)我在一个方法中调用它,结果哈希嵌套在我选择调用该方法的任何内容中。不是我的想法。
我的问题:有没有人成功创建了一个接受任何属性的序列化器?很想知道如何。
请注意:如果可以,我想用AMS实现这一点 - 我们正在为所有响应主体使用适配器用于JSON API。我宁愿做这个工作,然后初始化一个与我们每次响应不是AM实例时使用的json api标准相同的哈希。
对于那些可能偶然遇到同样问题的人来说,我最终组装了一个catch-all序列化器类,用于我想要渲染的任何不是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类的实例的任何东西呈现JSON api标准,或者我正在做外部API请求并存储在Hash中的任何东西。希望有一天能帮助某人。