微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何装饰来自第 3 方 API 的哈希对象 - Rails

如何解决如何装饰来自第 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 举报,一经查实,本站将立刻删除。