【问题标题】:Display list/or table with Ruby on Rails from search result从搜索结果中显示带有 Ruby on Rails 的列表/或表格
【发布时间】:2020-05-08 13:53:31
【问题描述】:

Ruby on Rails 的新手。在提交搜索参数后,我想更新 new.html.erb 视图以显示来自 album_controller.rb 的 search_result。我可以创建一个隐藏元素,然后通过控制器显示它吗? search_results 是一个字符串数组。

我的目标是显示可供选择的可能专辑列表(从 http get 请求中获得),然后让用户选择要继续使用哪个搜索结果。

new.html.erb

<h4>Search for Album</h4>

<%= form_with(url: "/albums/search", method: "get") do %>
  <%= label_tag(:q, "Search for: ") %>
  <%= text_field_tag(:q) %>
  <%= submit_tag("Search") %>
<% end %>

album_controller.rb

require 'httparty'
require 'json'

class AlbumsController < ApplicationController

  def new
    puts "the new method was just called"
  end

  def search
    puts "inside search method"
    @search_param = params[:q]
    puts @search_param

    if params[:q] # if not null
      #perform artist and album search
      search_result = http_request(@search_param)
    end
  end

  def http_request(search_input)
    # search for album
    website = "http://ws.audioscrobbler.com/2.0/?"
    search_album = "method=album.search&album=" + search_input + "&"
    api_key = "api_key=&"
    format = "format=json&"
    limit = "limit=15"

    url = website + search_album + api_key + format + limit

    response = HTTParty.get(url)
    pretty_json = JSON.pretty_generate(response.parsed_response)
    obj = JSON.parse(pretty_json)

    returnArray = []
    for result in obj["results"]["albummatches"]["album"]
      tempArray = [result["name"], result["artist"], result["image"][3]["#text"]]
      returnArray.append(tempArray)
    end

    return returnArray
  end
end

routes.rb

Rails.application.routes.draw do
  get 'welcome/index'

  post "albums/new" #to later post to album db

  get "albums/search"  #search route in new.html.erb

  resources :albums

  root 'welcome#index'

end

【问题讨论】:

  • 如果您想提交特定于专辑的搜索查询。为什么不像:Album.where(title: "inquery_data")
  • 相册obj尚未创建。我想显示一个可供选择的可能专辑列表(从 http get 请求中获得),然后让用户选择要继续使用哪个搜索结果。
  • 我不太明白这里的流程。您想给他们一个专辑列表以供选择,然后搜索该专辑选择导致的内容吗?似乎有点过于复杂。
  • 对不起,如果我不具体,第一次发帖。我想在数据库中维护个人专辑收藏。流程是这样的:搜索专辑(通过音乐api),http get请求返回json,将json解析成15个搜索结果,将搜索结果显示给用户(我现在遇到问题的地方),最后让用户选择将哪个搜索结果添加到数据库中。
  • 无法将该 json 放入视图中?

标签: html ruby-on-rails ruby


【解决方案1】:

在 Rails 中,您希望构建包含最少代码的瘦控制器,并且唯一的公共方法应该是与您的路由对应的操作。这是因为控制器是出了名的难以测试,而且膨胀很快就会成为一个问题。

HTTP 调用、批处理和其他此类任务不属于您的控制器。尤其是当它们触及应用程序边界时。相反,您希望创建一个客户端对象来处理 HTTP 调用和封装数据并为您的应用程序规范化数据的模型。

让我们从 HTTP 调用开始:

# app/clients/audio_scobbler_client.rb
class AudioScrobblerClient
  include Httparty
  format :json
  base_uri "http://ws.audioscrobbler.com/2.0/"

  def initialize(api_key:)
    @base_opts = {
      api_key: api_key,
      format: "json" # may be redundant
    }
  end

  def album_search(query, limit: 15)
    self.class.get(
      @base_opts.reverse_merge(
        method: 'album.search',
        limit: limit
      )
    )
  end
end

这为您提供了一个可以与控制器分开测试的对象,并消除了使用字符串连接构造查询字符串的麻烦(永远不要这样做)。它通过执行 HTTP 请求返回 JSON,仅此而已。

然后创建一个模型来表示您的应用程序中的搜索结果。请记住,持久性并不是 MVC 中模型的唯一作用。

# app/models/album.rb
class Album
  include ActiveModel::Model
  include ActiveModel::Attributes
  attr :artist, String
  attr :name, String
  attr :image, String
end

现在让我们再添加一个对象 - 一个执行 API 调用并规范化值的服务对象:

# app/services/audio_scrobbler_search.rb
class AudioScrobblerSearch
  def perform(query, **options)
    api_key = ENV["AUDIOSCROBBER_API_KEY"] # or use the encrypted secrets.
    json = AudioScrobblerClient.new(api_key: api_key).album_search(query, options)
    json.dig("results", "albummatches", "album").map do |result|
      # I have no idea what api response looks 
      # like but I have no doubt that you can figure this part out
      Album.new(
         artist: result["name"],
         name: result["name"],
         image: result["image"]
      )
    end
  end
end

然后让我们摆脱控制器中的所有臃肿:

class AlbumsController < ApplicationController
  # you don't really need the new action at all since a search form can just loop back on itself
  # GET /albums/search?q=believe
  def search
    @search_query = params[:q]
    if @search_query
      @albums = AudioScrobblerSearch.perform(query)
    end
  end
end

并列出视图中的专辑:

<h4>Search for Album</h4>

<%= form_with(url: "/albums/search", method: "get") do %>
  <%= f.label(:q, "Search for: ") %>
  <%= f.text_field(:q, value: @search_query) %>
  <%= f.submit("Search") %>
<% end %>

<% if @albums %>
  <table>
    <thead>
      <tr>
        <th>Image</th>
        <th>Artist</th>
        <th>Name</th>
      </tr>
    </thead>
    <tbody>
      <% @albums.each do |album| %>
        <tr>
          <td><%= tag.img src: album.image, alt: "Cover art for #{album.name}" %></td>
          <td><%= album.artist %></td>
          <td><%= album.name %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
<% elsif @search_query.present? %>
  <p>No results to display :(</p>
<% end %>

【讨论】:

  • 请注意,这个答案只是为了概述一般方法,我根本没有实际测试过 api 调用。您需要进行一些组装,并且很可能包含多个错误。
  • 谢谢你的详细回答,我现在正在处理它。我有个问题。在 audio_scrobbler_client 中,“self.get”的目的是什么。此时我得到一个 NoMethodError。
  • 同样在视图中,我看到你遍历@albums。但我不确定如何创建专辑列表。在 audio_scrobbler_search.rb 中,Album.new() 是否会创建一个新的专辑对象并将其附加到列表中?
  • No -Album.new(...) 只是创建一个 Album 的实例。查看它上面的行json.dig("results", "albummatches", "album") 获取密钥obj["results"]["albummatches"]["album"].map 遍历数组并返回一个新数组,其中包含块返回的值。 for 循环不被任何人使用,除了 ruby​​ 初学者。
  • 抱歉应该是self.class.get,它调用了HTTParty.get
猜你喜欢
  • 2014-06-19
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
  • 2012-07-23
  • 2013-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多