如何动态地向 ROAR 代表添加属性?
How to dynamically add properties to a ROAR representer?
我正在使用 ROAR 为 rails 应用程序实施 API。此应用程序处理的票证可以具有 subject 和 description 等属性,但也可以具有用户定义的属性。为简单起见,我们假设一张票看起来像:
class Ticket
attr_accessor :subject, :description
def custom_attributes
# in reality these attributes depend on the current ticket instance
# they are not hard-coded into the class
[['priority', 'high'], ['Operating System', 'Ubuntu']]
end
end
此类工单所需的 JSON 输出如下所示:
{
"subject": "Foo",
"description": "Bar",
"customField1": "high",
"customField2": "Ubuntu"
}
现在您可能已经看到问题了。所有属性都是根对象的直接子对象,这意味着我不能将其写为代表:
class TicketRepresenter
property :subject
property :description
# Need to iterate over instance members on the class level here...
end
ROAR 是否提供了一些机制来实现这一点?例如。在实际实例的上下文中执行的回调,例如
def call_me_on_write
represented.custom_attributes.each do |attribute|
add_property('customField1', attribute[1])
end
end
在 ROAR 中是否有类似的东西是我为了完成这个而忽略的?
我查看了 ROAR and the docs for representable 的两个文档,但找不到任何内容。
免责声明
我尽量简化实际情况,使问题更易读。如果您认为缺少重要信息,请告诉我。谢天谢地,我会提供更多详细信息。
超出范围
请不要讨论选择的JSON格式是否是good/bad想法,我想评估ROAR是否支持它。
我最终从我的基本代表动态创建了 classes:
class TicketRepresenter
property :subject
property :description
def self.create(ticket, context = {})
klass = Class.new(TicketRepresenter) # create a subclass of my representer
ticket.custom_attributes.each do |attribute|
# for each custom attribute in the actual instance insert a property into the created class
property "customField#{attribute.id}".to_sym
getter: -> (*) { attribute.value }
end
# return an instance of the class created above
klass.new(ticket, context)
end
end
基本上这意味着用于创建 JSON 的实际代表 class 对于每个 Ticket
.
都是不同的代表
如果您想从 JSON 读取 Ticket
返回,则必须正确初始化表示器,以便创建的表示器 class 知道您的自定义字段并定义二传手。
您现在需要按常规调用新的 create
方法而不是 new
。
如果您需要通过 ROAR 创建您的代表(例如,对于一个集合),您可以使用 ROAR 的 Polymorphic Object Creation 机制。
注意:上面的代码并不完全符合我问题中发布的自定义属性示例,但您应该明白了(在示例中,属性没有成员像 id
和 value
,但是由键和值组成的列表)。
我认为解决该问题的最佳方法是使用 Roar 的 writer:
。它通过将它调用的一些值 options 传递给提供的 lambda 来完全将对输出的控制权交给你。
例如:
property :desired_property_name, writer: -> (represented:, doc:, **) do
doc[:desired_key] = represented.desired_value
end
github 自述文件未涵盖但在 Trailblazer 网站上记录了很多用途。这个可以在 http://trailblazer.to/gems/representable/3.0/function-api.html#writer 找到。
干杯!
我正在使用 ROAR 为 rails 应用程序实施 API。此应用程序处理的票证可以具有 subject 和 description 等属性,但也可以具有用户定义的属性。为简单起见,我们假设一张票看起来像:
class Ticket
attr_accessor :subject, :description
def custom_attributes
# in reality these attributes depend on the current ticket instance
# they are not hard-coded into the class
[['priority', 'high'], ['Operating System', 'Ubuntu']]
end
end
此类工单所需的 JSON 输出如下所示:
{
"subject": "Foo",
"description": "Bar",
"customField1": "high",
"customField2": "Ubuntu"
}
现在您可能已经看到问题了。所有属性都是根对象的直接子对象,这意味着我不能将其写为代表:
class TicketRepresenter
property :subject
property :description
# Need to iterate over instance members on the class level here...
end
ROAR 是否提供了一些机制来实现这一点?例如。在实际实例的上下文中执行的回调,例如
def call_me_on_write
represented.custom_attributes.each do |attribute|
add_property('customField1', attribute[1])
end
end
在 ROAR 中是否有类似的东西是我为了完成这个而忽略的?
我查看了 ROAR and the docs for representable 的两个文档,但找不到任何内容。
免责声明
我尽量简化实际情况,使问题更易读。如果您认为缺少重要信息,请告诉我。谢天谢地,我会提供更多详细信息。
超出范围
请不要讨论选择的JSON格式是否是good/bad想法,我想评估ROAR是否支持它。
我最终从我的基本代表动态创建了 classes:
class TicketRepresenter
property :subject
property :description
def self.create(ticket, context = {})
klass = Class.new(TicketRepresenter) # create a subclass of my representer
ticket.custom_attributes.each do |attribute|
# for each custom attribute in the actual instance insert a property into the created class
property "customField#{attribute.id}".to_sym
getter: -> (*) { attribute.value }
end
# return an instance of the class created above
klass.new(ticket, context)
end
end
基本上这意味着用于创建 JSON 的实际代表 class 对于每个 Ticket
.
如果您想从 JSON 读取 Ticket
返回,则必须正确初始化表示器,以便创建的表示器 class 知道您的自定义字段并定义二传手。
您现在需要按常规调用新的 create
方法而不是 new
。
如果您需要通过 ROAR 创建您的代表(例如,对于一个集合),您可以使用 ROAR 的 Polymorphic Object Creation 机制。
注意:上面的代码并不完全符合我问题中发布的自定义属性示例,但您应该明白了(在示例中,属性没有成员像 id
和 value
,但是由键和值组成的列表)。
我认为解决该问题的最佳方法是使用 Roar 的 writer:
。它通过将它调用的一些值 options 传递给提供的 lambda 来完全将对输出的控制权交给你。
例如:
property :desired_property_name, writer: -> (represented:, doc:, **) do
doc[:desired_key] = represented.desired_value
end
github 自述文件未涵盖但在 Trailblazer 网站上记录了很多用途。这个可以在 http://trailblazer.to/gems/representable/3.0/function-api.html#writer 找到。
干杯!