Показать список / или таблицу с Ruby в Rails из результатов поиска - PullRequest
0 голосов
/ 08 мая 2020

Новое в Ruby на Rails. Я хочу обновить новое представление. html .erb, чтобы отображать search_result из album_controller.rb после отправки параметра поиска. Могу ли я создать скрытый элемент, а затем отобразить его через контроллер? search_results - это массив строковых массивов.

Моя цель - отобразить список возможных альбомов на выбор (полученный из HTTP-запроса на получение), а затем позволить пользователю выбрать, с каким результатом поиска продолжить.

новый. 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

маршруты .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

1 Ответ

1 голос
/ 08 мая 2020

В Rails вы хотите создавать тонкие контроллеры, содержащие минимум кода, и единственными c методами должны быть действия, соответствующие вашим маршрутам. Это связано с тем, что контроллеры, как известно, сложно тестировать, и раздувание становится проблемой очень быстро.

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

Это дает вам объект, который вы можете протестировать отдельно от вашего контроллера, и устраняет беспорядок при построении строк запроса с конкатенацией строк (никогда не делайте этого). Он возвращает JSON от выполнения HTTP-запроса и ничего более.

Затем создайте модель, которая представляет результаты поиска в вашем приложении. Помните, что постоянство - не единственная роль моделей в 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 %>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...