こちらの記事の続きです。
前回はAPI連携後にviewファイルを表示させていましたが、今回はajax通信でデータを取得して書籍検索結果を表示します。
(理由はこの方がかっこいいからです笑)
完成イメージ
(cssで見た目を少し整えたので、前回の記事と少し見た目は変わってます)
処理の流れ
検索フォームに入力して検索ボタンを押す(submitする)と以下のように処理されます
1. 検索フォームのキーワードを取得
2. json形式でデータ(キーワード)を持たせて、指定のURLにリクエスト(ajax通信)
3. コントローラでAPI連携の処理をし、jsonでデータを渡す
4. 返ってきたデータを使ってhtmlを書き換えて検索結果を表示
各ファイル
コントローラ
コントローラにjsonでレスポンスを返すという記述が必要です。
respond_to 〜
のところ
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
views/[コントローラ名と同じ名前のディレクトリ]
の中にindex.json.jbuilder
を作成します。
今回はcontrollers
直下にsearches_controller.rb
を作っているので、views/searches/index.json.jbuilder
となります。
今回jsonデータは配列になっているので、各要素をどのように加工するか書く必要があります。取り出すデータは画像、タイトル、著者、出版社の情報にしています。
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ファイル
// jQueryを使って記述します
$(function() {
// 検索結果を表示する関数
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);
}
// 検索中の表示関数
function dispLoading(msg){
let dispMsg = "<div class='loadingMsg'>" + msg + "</div>";
$("body").append("<div id='loading'>" + dispMsg + "</div>");
}
// 検索中の表示を消す関数
function removeLoading(){
$("#loading").remove();
}
// 検索ボタンを押した時にイベント発火
$("#book-search-form").on("submit", function(e) {
e.preventDefault();
const keyword = $("#keyword").val();
dispLoading("検索中...");
// ajax通信の詳細
$.ajax({
url: '/searches',
type: 'GET',
data: {'keywords': keyword},
dataType: 'json',
timeout: 10000
})
// ajaxがうまくいったとき
.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 = '不明な作者'
} else {
author = `${item.authors[0]}`
}
if (item.publisher == null) {
publisher = '不明な出版社'
} else {
publisher = item.publisher
}
let title = item.title
appendBook(image_url, title, author, publisher);
})
})
// ajaxが失敗した時
.fail(function(){
alert("検索に失敗しました");
})
// ajaxが成功しても失敗しても共通の処理
.always( function(data) {
// Lading 画像を消す
removeLoading();
});
});
})
コードを読めばわかると思いますが、処理の流れを書いてみます。
■ 関数の定義
- appendBook
本のデータを元にhtml作成する関数 - dispLoading
検索中のgifファイルを表示させる関数 - removeLoading
検索中のgifファイルを非表示にする関数
■ イベント
- submitアクションでイベント発火
- フォームに入力されたキーワードを取得
- 検索中の画面を表示
- ajax通信のリクエスト(urlや送信データを指定)
- ajax通信が成功したときの処理
各データを変数にして、appendBook関数に食わせる
(データが取得できない場合は不明な作者などのデータが入るようにしておく) - ajax通信が失敗したときの処理
- 共通処理として検索中の画像を消す
検索に少し時間がかかるので、検索中であることがわかりやすいように、ajax通信中はgif画像を表示させるようにしています。
また、検索に時間がかかりすぎた場合にエラーになるようにしています。(10秒)
ずっと検索中になっているとユーザー側が不安になるので。
検索中の画面(cssファイル)
#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;
}
gifファイルは無料で作れるサイトがいくつかあるので作ってみましょう。
僕はこのサイトでつくりました。
メモ
うまくいかなかった部分をメモに残しておきます。
(詳しい方は教えていただけると嬉しいです…)
-
本当はkeyword_paramsだけを引数にしたい
コントローラでkeywordを元にAPIを叩く際に、search_itemsの引数にはkeyword_params
としてハッシュ形式で渡せばスッキリするのですが、なぜかうまくいきませんでした。(activehashだと受け取ってくれない感じ…) -
turbolinksを消すとうまく作動しない
turbolinksが入っているとajax通信する際にうまくいかないことがあるらしく、いつも使わない設定にしていたのですが、逆にturbolinksがないせいでajax通信がうまく行かないという事態になりました笑。この辺の仕組みはいまいち理解できてません…