【Rails】Amazon APIで書籍検索アプリ作成

  • 140
    Like
  • 1
    Comment
More than 1 year has passed since last update.

概要

以前使用したAmazon APIについてまとめておきたいな〜と思いまして。。。。。
実際に導入から実装までの流れを含め、簡単な書籍検索アプリを作ってみました!
作成するアプリの内容としては、
検索ボックスにキーワードを書き込み、その検索結果を返してくれるというシンプルなものです!

さらに!
おまけとしてJSを適用させて、インクリメンタルサーチを行えるようにもしたいと思います!

実際はこんな感じで動きます。
moview.gif

環境

Ruby 2.1.3
Rails 4.2.4

目次

  1. アプリケーションの作成,基本的な実装
  2. AmazonアソシエイトIDとAccess Keyの取得
  3. Amazon APIを実際を使用して書籍検索機能の実装
  4. インクリメンタルサーチの実装

実装

1. アプリケーションの作成,基本的な実装

アプリケーションの作成、routing, controllerの作成,viewの作成を行います。

1.1 アプリケーションの作成

書籍検索アプリなので、アプリ名はbook_searchとします。

$ rails new book_search
$ cd book_search

現在の最新版(2015年12月)のgem mysql2のバージョンだとエラーが生じるので、バージョンを書き換えます。
デバックの際に使用するpry-railsを入れておきましょう。

gem 'mysql2', '0.3.18'
gem 'pry-rails 

DBの作成を行っておきます。

$ bundle install
$ rake db:create

1.2 基本的な実装

コントローラー、モデルの作成を行いましょう。
controller名は、books_controllerとします。
ヘルパーとアセットファイルを生成する必要がないので、オプションをつけて作成しないようにします。
また、モデルに関しては、DBへのアクセスは必要がないので、ActiveRecordを継承しないモデル(参考サイト)を作成します。

$ rails g controller books --assets false --helper false

では、ルーティングの設定, コントローラーにおけるアクションの定義、viewの編集を行いましょう。
ここも基礎の部分なので、説明は省略させていただきます。

routes.rb
Rails.application.routes.draw do
  root to: 'books#search'
end
books_controller.rb
class BooksController < ApplicationController
  def search
  end
end
book.rb
class Book
  # プロパティの設定
  attr_accessor :title, :image_url, :url 

  def initialize(title, image_url, url)
    @title = title
    @image_url = image_url
    @url = url
  end
end
search.html.erb
<div class='content'>
  <div id="search-box">
    <%= form_tag('/', method: :get) do %>
        <%= text_field_tag :book, "",  id: "book_search", name: "keyword", placeholder: "キーワードを打ち込んでください", style: "width: 200px;"%><button title="検索" type="submit">検索</button>
    <% end %>
  </div>
  <h2>検索結果</h2>
  <div id='book_list'>
    <!-- コメントアウトしておく -->
   <!-- <%= render partial: 'book_list' %> -->
  </div>
</div>
_book_list.html.erb
<% if @books.present? %>
  <% @books.each do |book| %>
    <div class="list">
      <%= link_to (image_tag(book.image_url, style: "width: 70px;height: 100px;display: inline-block;")), book.url %>
      <%= book.title %>
    </div>
  <% end %>
<% end %>

2. AmazonアソシエイトIDとAccess Key IDの取得

Amazon APIを使用するにあたって、以下のキーが必要となります。

  • associate_tag
  • AWS_access_key_id
  • AWS_secret_key

associate_tagはAmazonアフィリエイトアカウントを登録することで、取得できます。
また、AWS_access_key_idAWS_secret_keyはProduct Advertising APIに登録することで取得することができます。
何か分からないことがありましたら、こちら(Access Key IDとSecret Access Keyの取得)を参照ください。

2.1 AmazonアソシエイトIDの作成

AmazonアソシエイトIDの作成はこちらから行いましょう。
このとき、AmazonアソシエイトIDはログインページの右上のあるのが、覚えておいてください。

2.2 Product Advertising APIアカウント作成

Access Keyを取得するためには、Product Advertising APIアカウント作成を行う必要があります。

先ほど登録したAmazonアソシエイトのページから
以下の写真のようにメニュータブのProduct Advertsing APIをクリックしてアカウント作成ボタンをクリックします。
Presentation1.png

注意点としては、

  • Amazonアソシエイトで使用した同じメールアドレスを指定すること。
  • すべて英語で入力すること。

です。

2.3 Access Key IDSecret Access Keyの取得

登録が完了できたら以下のようにして、2つのAccess Keyを確認することができます。
注意として、シークレットキーは絶対に公開にしないようにしてください。

Presentation2.png

3 Amazon APIを実際に使用する

ついにAmazon APIを使用する下準備が整いました!!
これらカリカリとコードを書いていきます!!!
APIを使用し検索結果を表示するにあたって、以下の手順を踏みます。

  • gemのamazon-ecsの追加、設定ファイルの記述
  • コントローラーの編集
  • Viewに検索結果を表示

3.1 gemのamazon-ecsの追加、設定ファイルの記述

Amazon APIを使用するにあたって、amazon-ecsというgemを使用します。(リポジトリはこちら)

gem 'amazon-ecs'

config/environment.rbにて、gemでインストールしたAmazon::Escを読み込みAmazon Web Serviceを利用するためのAPI Key設定します。
自身のアソシエイトキーとアクセスキーを指定します。

config/environment.rb
Amazon::Ecs.options = {
      associate_tag:     '**************',
      AWS_access_key_id: '*****************',
      AWS_secret_key:   '***********************'
}
$ bundle install

3-2 コントローラーの編集

ここからAmazon Web Serviceにアクセスするための記述を行っていきます。
ソースコードは以下になります。

boooks_controller.rb
class BooksController < ApplicationController
  def search
    if params[:keyword].present?
      # デバックログ出力するために記述
      Amazon::Ecs.debug = true

      # Amazon::Ecs::Responceオブジェクトの取得
      books = Amazon::Ecs.item_search(
        params[:keyword],
        search_index:  'Books',
        dataType: 'script',
        response_group: 'ItemAttributes, Images',
        country:  'jp',
        power: "Not kindle"
      )

      # 本のタイトル,画像URL, 詳細ページURLの取得
      @books = []
      books.items.each do |item|
        book = Book.new(
          item.get('ItemAttributes/Title'),
          item.get('LargeImage/URL'),
          item.get('DetailPageURL'),
        )
        @books << book
      end
    end
  end
end

ひとつひとつ説明していきたいと思います。

Amazon::Ecs.debug = true

有効にすることで、以下の写真のように、デバックログが出力され、検索するにあたってどのような指定を行っているのか、また、エラー時にはエラー内容が出力されます。
さらに注目すべきは、amazon-ecsがリクエストしたURLも出力されているので、URLからAPIのリクエストの実行結果も見ることができます。

スクリーンショット_2015-12-10_11_10_33.png

Amazon::Ecs::Responseオブジェクトの取得

item_searchメソッド
幾つかの検索条件を満たす商品のXML要素の情報を配列として返します。
また、一度の検索に検索に最大10個の検索結果を返します。

今回の指定した引数に関しての説明をしていきたいと思います。

  • 第一引数に、自身が打ち込んだキーワード
  • 第二引数のseach_indexにて検索対象の指定を行う。Booksとしているので、検索対象は本としている。詳しくは、パラメータの組み合わせはこちらを参照してください。
  • 第三引数のresponce_groupでは、レスポンスの情報量を制御します。情報量を適切に保つには、ご使用のアプリケーションが必要とする情報だけを返すレスポンスグループを指定します。 商品の詳細情報と画像情報が欲しいのでItemAttributesとImageを指定します。 詳しいレスポンスグループの指定はこちら
  • 第四引数のcountryには地域の指定をします。
  • 第五引数power: "Not kindle"と指定することで、検索結果からkindleの除外することがすることができます。参考URL:kindleを検索結果から除外する

ほかにも色々なオプションがありますので、気になる方はご自身で調べてみてください。

本のタイトル,画像URL, 詳細ページURLの取得

Amazon::Ecs::Responseのインスタンスbooksから必要な情報を取得します。
今回必要な情報は、タイトル,画像URL,詳細ページのURLです。
変数のbooksがどのような構造をしているか確認したい場合には、binding.pryを使用する、あるいは、コンソールで出力されているAPIリクエストのURLから確認することができます。
必要な要素の取得はgetメソッドを使って取得できます。

取得結果をインスタンス変数@booksに渡してviewに渡すことができます。

Viewに検索結果を表示

search.html.erbのコメントアウトしていた箇所を解除してみましょう。

こんな感じになりましたか??
ひとまずはAmazon APIの導入から実装までは以上です!

moview.gif

4. インクリメンタルサーチの実装

ここは主題ではないので、簡単にソースコードの紹介とさせていただきます。
インクリメンタルサーチを行うにあたって、以下のファイルを生成、編集します。

  • incremental_search.js
  • search.js.erb

incremental_search.jsはassets/javascripts/に置き、
search.js.erbはview/books/に置きます。

では、jsをカキカキしていきましょう。
下に示すソースコードはあくまでも一例です。

incremental_search.js
$(window).on('load', function() {
  var timer;
  var preInput = "";

  ajaxSearch = function(input) {
    $.ajax({
      url: "/",
      type: "GET",
      dataType: 'script',                          // jsファイルを指定したいので、dataTypeをscriptに指定
      data: ("keyword=" + input)
    });
  };

  triggerAjax = function(input) {
    if(preInput !== input){                        //文字列が変更ときのみメソッド実行する
      clearTimeout(timer);
      timer = setTimeout(ajaxSearch, 500, input); // 処理を500ms毎に実行
    };
  };


  $('#book_search').on('keyup', function() {
    input = $.trim($(this).val());                // 文字列の先頭と末尾の空白を削除
    triggerAjax(input);
    preInput = input;
  });
});
search.js.erb
$("#book_list").html("<%= j(render 'book_list') %>");

これで検索ボタンをいちいち押す必要がなくなり、検索もスイスイ行うことが可能です!
完成!!

moview.gif

This post is the No.10 article of TECH::CAMP Advent Calendar 2015