[Rails] Book search (asynchronous communication) with Amazon PA API v5.0

This is a continuation of this article.

Last time, the view file was displayed after API linkage, but this time, the data is acquired by ajax communication and the book search result is displayed. (The reason is that this is cooler lol)

Complete image

ee6e3c4e9c998d33288b32bff916570d.gif

(Since the appearance has been adjusted a little with css, the appearance is a little different from the previous article)

Process flow

If you fill in the search form and press the search button (submit), it will be processed as follows

  1. Get keywords in the search form
  2. Have data (keyword) in json format and request to the specified URL (ajax communication)
  3. Process API linkage with controller and pass data with json
  4. Rewrite html using the returned data and display the search results

Each file

controller

It is necessary to describe that the response is returned by json to the controller. At respond_to ~

searches_controller


class SearchesController < ApplicationController
  before_action :call_client, only: :index
  
  def index
    si = @client.search_items(keywords: keyword_params, SearchIndex: "Books")
    @items = si.items
    respond_to do |format|
      format.html
      format.json
    end
  end
  
  private
  
  def call_client
    require 'paapi'
    @client = Paapi::Client.new(access_key: Rails.application.credentials[:pa_api][:access_key_id],
                                secret_key: Rails.application.credentials[:pa_api][:secret_key],
                                market: :jp,
                                partner_tag: Rails.application.credentials[:pa_api][:associate_tag])
  end
  
  def keyword_params
    params.require(:keyword)
  end

end

jbuilder Create ʻindex.json.jbuilder in views / [directory with the same name as the controller name]. This time, searches_controller.rb is created directly under controllers, so it will be views / searches / index.json.jbuilder`.

Since the json data is an array this time, it is necessary to write how to process each element. The data to be extracted is the information of the image, title, author, and publisher.

ruby:index.json.jbuilder


json.array! @items do |item|
  json.image_url item.image_url
  json.title item.title
  json.authors item.authors
  json.publisher item.publisher
end

js file

api-search.js


//Write using jQuery

$(function() {

  //Function to display search results
  let search_list = $("#books")
  function appendBook(image_url, title, author, publisher) {
    const html = `<div class="search-book-content">
                  <div class="book-image">
                    <img class="book-image" src="${image_url}">
                  </div>
                  <div class="right-content">
                    <div class="book-info">
                      <div class="book-info__title">
                        ${title}
                      </div>
                      <div class="book-info__author">
                        ${author}
                      </div>
                      <div class="book-info__publisher">
                        ${publisher}
                      </div>
                    </div>
                  </div>
                </div>`
    search_list.append(html);
  }

  //Display function being searched
  function dispLoading(msg){
    let dispMsg = "<div class='loadingMsg'>" + msg + "</div>";
    $("body").append("<div id='loading'>" + dispMsg + "</div>");
  }

  //Function to turn off the display during search
  function removeLoading(){
    $("#loading").remove();
  }

  //Event fires when the search button is pressed
  $("#book-search-form").on("submit", function(e) {
    e.preventDefault();
    const keyword = $("#keyword").val();
    dispLoading("Searching...");

    //Details of ajax communication
    $.ajax({
      url: '/searches',
      type: 'GET',
      data: {'keywords': keyword},
      dataType: 'json',
      timeout: 10000
    })
    
    //When ajax works
    .done(function(items){
      $(".search-book-content").remove();
      items.forEach(function(item){
        let image_url;
        let author;
        let publisher;
        if (item.image_url == null) {
          image_url = `/assets/no_image-267acfcb976ba4942183409c682b62a768afb48c328b6ba60de7b57fd83c3b56.png`
        } else {
          image_url = item.image_url
        }
        if (item.authors.length == 0) {
          author = 'Unknown author'
        } else {
          author = `${item.authors[0]}`
        }
        if (item.publisher == null) {
          publisher = 'Unknown publisher'
        } else {
          publisher = item.publisher
        }
        let title = item.title
        appendBook(image_url, title, author, publisher);
      })
    })
    //When ajax fails
    .fail(function(){
      alert("Search failed");
    })
    //Common processing regardless of whether ajax succeeds or fails
    .always( function(data) {
      //Lading Erase the image
      removeLoading();
    });
  });
})

As you can see by reading the code, let's write the process flow.


■ Function definition

  1. appendBook
    Function to create html based on book data
  2. dispLoading
    Function to display the gif file being searched
  3. removeLoading
    Function to hide the gif file being searched

■ Event

  1. Event fired by submit action
  2. Get the keywords entered in the form
  3. Display the screen being searched
  4. Ajax communication request (specify url and transmission data)
  5. Processing when ajax communication is successful
    Make each data a variable and feed it to the appendBook function (If data cannot be obtained, make sure that data such as unknown authors is entered)
  6. What to do when ajax communication fails
  7. Delete the image being searched as a common process

Since it takes a little time to search, I try to display a gif image during ajax communication so that it is easy to understand that the search is in progress.

Also, if the search takes too long, an error will occur. (10 seconds) If you keep searching, the user will be worried.

Searching screen (css file)

css file



#loading {
  display: table;
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background-color: #fff;
  opacity: 0.8;
}

#loading .loadingMsg {
  display: table-cell;
  text-align: center;
  vertical-align: middle;
  padding-top: 140px;
  background: image-url("loading.gif") center center no-repeat;
}

There are several sites where you can create gif files for free, so let's create them. I made it on this site.

Note

Make a note of what went wrong. (I would be grateful if you could tell me more about it ...)

Recommended Posts

[Rails] Book search (asynchronous communication) with Amazon PA API v5.0
[Rails] Book search with Amazon PA API
Using PAY.JP API with Rails ~ Card Registration ~ (payjp.js v2)
API (when implementing asynchronous communication)
API creation with Rails + GraphQL
Timeless search with Rails + JavaScript (jQuery)