はじめに
ポートフォリオ等でwebアプリを開発していると、「外部APIを利用してみたい」という方もいるかと思います。
今回紹介する楽天APIに関しては、データを取得すること自体は、そんなに難しくありません。
アプリIDを取得してgemをインストールすれば、割と簡単にデータを取得することができます。
ただし、「APIのデータをテーブルに格納して他のテーブルと関連付けて…」というように、取得したデータをアプリ内で活用しようとするとやや難易度が上がります(個人的な考えですが笑)
本記事では「取得したデータをテーブルに格納する方法」と「アソシエーションの設定」について記載していきます。
また、最後にアプリ内で検索機能を設けて、必要なデータを表示させるコードも簡単に記載しました。
これから楽天APIを使ってみたいという方の参考になれば幸いです。
注意
- 
本記事は楽天APIについて言及しております。 
 また楽天APIにも様々ありますが、今回は楽天ブックス書籍検索APIを用います。
- 
本記事では、APIのデータ取得の部分(アプリIDの取得とgemのインストール)は割愛します。 
 データ取得部分については、以下の記事を参考にしてみてください。
 
 https://freesworder.net/rakuten-api-rails/
 https://qiita.com/hakusai_it/items/6453c4577647cb8995d3
環境
- Ruby version 2.7.2
- Rails version 6.0.3.4
ER図
今回は以下のER図にて、話を進めていきます。
Bookテーブルがデータを格納するテーブルです。
取得した本について、レビューを記載するために、Reviewテーブルを設けています。
Bookテーブルのカラムについて少し説明します。
今回Bookテーブルのprimary_keyは『id』ではなく、商品の固有の番号である『isbn』を使っていきます。
『title』,『author』はそれぞれ、本のタイトルと著者名です。
『item_caption』は商品の説明、『item_url』は楽天の商品のurl、『middleimage_url』は本の画像です。
その他にも様々なデータがありますので、気になる方は以下のURLを参考にしてください。
https://webservice.rakuten.co.jp/api/booksbooksearch/
実装工程
概要
以下のような流れで実装していきます。
step1. テーブルの作成
step2. アソシエーションの設定
step3. ルーティングの設定
step4. コントローラーの設定
step5. 検索ページの作成
「アソシエーションの設定」はstep1・step2、
「取得したデータをテーブルに格納」はstep3・step4、
「検索ページの実装」はstep5で実装します
step1. テーブルの作成
各テーブルを作成していきます。
前述の通り、今回は User, Book, Reviewテーブルを作っていきます。
Userテーブル作成
Userテーブルは特に変わったことはしません。
モデルを作成して、マイグレーションを実行していきましょう!
$ rails g model User name:string email:string password_digest:string
$ rails g db:migrate
Bookテーブル作成
まずはモデルを作成していきます。
$ rails g model Book title:string author:string isbn:bigint url:string image_url:string
次にmigrationファイルを書き換えていきます。
Bookテーブルのprimary_keyは『id』ではなく、商品の固有の番号である『isbn』を使っていくため、ファイルの書き換えが必要になります。
ファイル名の米印にはMigration ID(日付等が書いてある数字)が入ります。
ActiveRecord::Migration[6.0]の部分は人によって異なると思います。
isbn部分にnull: false, primary_key: trueを追記します。
class CreateBooks < ActiveRecord::Migration[6.0]
  def change
    create_table :books, id: false do |t|
      t.string :title
      t.string :author
      t.bigint :isbn, null: false, primary_key: true
      t.string :url
      t.string :image_url
      t.timestamps
    end
  end
end
マイグレーションファイルを書き換えたらマイグレーションしていきます。
$ rails g db:migrate
Reviewテーブル作成
最後にReviewテーブルを作成していきます。
$ rails g model Review content:string user:references book:references
次にmigrationファイルを書き換えていきます。
ファイル名の米印にはMigration ID(日付等が書いてある数字)が入ります。
ActiveRecord::Migration[6.0]の部分は人によって異なると思います。
class CreateReviews < ActiveRecord::Migration[6.0]
  def change
    create_table :books, id: false do |t|
      #bookの部分に記載してあったforeign_key: trueを削除する
      t.references :book, null: false
      t.references :user, null: false, foreign_key: true
      t.timestamps
    end
    #この部分の新たに以下のコードを記載
    add_foreign_key :bookcases, :books, column: :book_id , primary_key: :isbn
  end
end
マイグレーションファイルを書き換えたらマイグレーションを実行していきます。
$ rails g db:migrate
これでテーブルの作成は以上です。
次はアソシエーションの設定です。
step2. アソシエーションの設定
各model.rbのアソシエーションを設定してきます。
ここでもBookテーブルのprimary_keyを『isbn』になるようコードを書いていきます。
class User < ApplicationRecord
  has_many :reviews, dependent: :destroy
end
class Book < ApplicationRecord
  self.primary_key = "isbn"
  has_many :reviews, dependent: :destroy
end
class Bookcase < ApplicationRecord
  belongs_to :user
  belongs_to :book, primary_key: "isbn"
end
step2までで、テーブル作成とアソシエーションの設定は終了です。
step3以降はBookテーブルにデータを格納する方法を主に説明していきますので、User, Reviewモデルについては割愛し、Bookモデルについてのみ記載していきます。
step3. ルーティングの設定
今回は検索欄と検索結果を表示するために/searchアクションを設けています。
必要であれば、ご自身で追加のアクションを設定してください。
get 'books/search', to: "books#search"
step4. コントローラの設定
まずはコントローラファイルを作成していきます。
$ rails g controller books
作成したコントローラファイルに以下のコードを記載していきます。
class BooksController < ApplicationController
  def search
    #ここで空の配列を作ります
    @books = []
    @title = params[:title]
    if @title.present?
      #この部分でresultsに楽天APIから取得したデータ(jsonデータ)を格納します。
      #今回は書籍のタイトルを検索して、一致するデータを格納するように設定しています。
      results = RakutenWebService::Books::Book.search({
        title: @title,
      })
      #この部分で「@books」にAPIからの取得したJSONデータを格納していきます。
      #read(result)については、privateメソッドとして、設定しております。
      results.each do |result|
        book = Book.new(read(result))
        @books << book
      end
    end
    #「@books」内の各データをそれぞれ保存していきます。
    #すでに保存済の本は除外するためにunlessの構文を記載しています。
    @books.each do |book|
      unless Book.all.include?(book)
        book.save
      end
    end
  end
  private
  #「楽天APIのデータから必要なデータを絞り込む」、且つ「対応するカラムにデータを格納する」メソッドを設定していきます。
  def read(result)
    title = result["title"]
    author = result["author"]
    url = result["itemUrl"]
    isbn = result["isbn"]
    image_url = result["mediumImageUrl"].gsub('?_ex=120x120', '')
    book_genre_id = result["booksGenreId"]
    item_caption = result["itemCaption"]
    {
      title: title,
      author: author,
      url: url,
      isbn: isbn,
      image_url: image_url,
      book_genre_id: book_genre_id,
      item_caption: item_caption
    }
  end
end
step4までで、テーブルへのデータ格納は実装完了です。
step5では検索ページと結果の出力ページを作成していきます。
step5. 検索ページの作成
search.html.erbというファイルを作成し、コードを書いていきます。
※本記事では最低限のコードのみ記載しております。適宜classを設定し、見た目を改善しましょう!
# 検索バーを表示
<%= form_tag(books_search_path, method: :get) do %>
  <%= text_field_tag :title, @title %>
  <%= button_tag type: "submit" %>
<% end %>
# 検索結果を表示
<% if @books %>
  <% @books.each do |book| %>
  #ご自身が表示させたいデータを記載してください。
  #以下のコードではは画像、タイトル、著者名、商品の説明を表示させています。
    <%= image_tag book.image_url %>
    <%= book.title %>
    <%= book.author %>
    <%= book.item_caption %>    
  <% end %>
<% end %>
以上で実装工程は終了となります。
何かご不明点や誤っている点がございましたら、コメントにて教えていただけると幸いです。

