如何解决如何装饰来自第 3 方 API 的哈希对象 - Rails
我在 Rails 应用程序中使用外部 3rd 方 API,我想知道我应该如何最好地处理响应,以便我可以向视图中的每个对象添加功能。
我有一个搜索框,可以触发对外部博物馆 API 的调用。我有一个处理调用和解析响应的服务对象,因此我可以确保结构一致。 然后,我将在列表中展示返回的项目,以便可以将单个项目导入到应用中。
我想为列表中的每个项目添加一个缩略图图像,其中图像 ID 存在于 API 响应中,或者添加一个占位符不存在的位置。我正在用我想提取的视图中的一些逻辑来处理这个问题。
<% @mus_objects.each do |ob| %>
<div class="row mt-5">
<div class="col-lg-6">
<% if ob['_primaryImageId'] %>
<%= image_tag("https://iiif_image_server_example.com/#{ob['_primaryImageId']}/full/!140,140/0/default.jpg") %>
<% else %>
<%= image_tag("https://placehold.it/140x140?text=No+Image") %>
<% end %>
<%= ob["_primaryTitle"] %>
<%= link_to 'Import',new_admin_museum_object_path(ob) %>
</div>
</div>
<% end %>
这是我的控制器代码:
class Admin::MuseumApiController < ApplicationController
def search
@search_term = params[:search_term]
if params[:searchtype] == 'search_term'
response = Museumapimanager::FetchBySearchTerm.call(@search_term)
elsif params[:searchtype] == 'systemNumber'
response = Museumapimanager::FetchBySystemNumber.call(@search_term)
end
if response && response.success?
@mus_objects = response["records"]
end
end
end
来自我的服务对象调用的响应如下所示:
#<OpenStruct success?=true,records=[{"systemNumber"=>"O123","objectType"=>"Bottle","_primaryTitle"=>"Bottle","_primaryImageId"=>'1234'}]>
所以视图使用的@mus_objects 是一个哈希数组。
我不确定处理这个问题的最佳方法是什么。我认为像装饰器这样的东西是合适的,这样我就可以在视图中调用 ob.thumbnail_url
但装饰器需要一个模型。
**** 尝试使用 ActiveModel 提出的答案 ****
我已经按照建议创建了一个 PORO 并将搜索方法引入这里,尽管就在我测试它时,我已经将逻辑留在了 ServiceObject 中。
class MuseumApiObject
include ActiveModel::Model
def self.fetch_by_search_term(search_term)
response = Museumapimanager::FetchBySearchTerm.call(search_term)
response["records"]
end
def thumbnail_url
if _primaryImageId
"https://iiif_example.com/#{_primaryImageId}/full/!140,140/0/default.jpg"
else
'https://placehold.it/140x140?text=No+Image'
end
end
end
现在在控制器中我正在这样做:
class Admin::MuseumApiController < ApplicationController
def search
@search_term = params[:search_term]
@mus_objects = MuseumApiObject.fetch_by_search_term(@search_term)
end
end
现在这仍然只是创建一个哈希数组。如何将这个散列数组实例化为 MuseumApiObjects 的负载?我尝试将 create 与数组一起使用,但它不存在。
解决方法
我更喜欢创建模型对象(而不是 ActiveRecord)来在我的代码(而不是服务)中封装域逻辑。这可以通过在 PORO 中包含 ActiveModel::Model
来实现。
此策略允许我将所有业务逻辑保留在我的模型中,现在并非所有模型都需要关联表。另外,我仍然可以获得验证和回调等所有优点,而且我还可以像编写任何其他模型一样编写测试用例。
在您的特定用例中,我将创建一个 MuseumObject
模型类(其中可能还包括 API 交互的逻辑),以及 thumbnail_url
方法。
class MuseumObject
include ActiveModel::Model
attr_accessor :system_number,:object_type,primary_title,primary_image_id
def initialize(attributes)
self.system_number = attributes['systemNumber']
...
end
def self.search
...
end
def thumbnail_url
...
end
end
编辑:
您将需要使用哈希初始化对象。您可以为所有字段定义 attr_accessor
,然后您可以简单地使用哈希值初始化对象。
例如,如果您的哈希数组存储在 museum_hashes
变量中,您可以将其转换为模型对象数组,
museum_hashes.map { |hash| MuseumObject.new(hash) }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。