0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Ruby on Rails】ポケモンゲットだぜ!!

Last updated at Posted at 2022-07-22

はじめに

本投稿はPokeAPIを使ってポケモンを検索し、
それをゲットだぜ!することで、データベースに保存する、というアプリを作成していきます。

PokeAPIについて

Poke APIにはポケモン関連のデータが大量にあります。
トップページでAPIを簡単に試せるようになっているので、ぜひ触ってみてください。
なお、今回作るアプリケーションでは取得できるデータのほんの一部しか使いません。

実装

1. Gemfileにgemを追加する

GemfileにFaradayというGemを入れます。

  • Faradayのざっくり説明
    • HTTPクライアントライブラリ。
    • Rubyの標準ライブラリのnet/httpでもHTTPリクエストはできますが、Faradayはより簡単にHTTPリクエストを行うことができる。
Gemfile
gem 'faraday' # 追加する
コマンドプロンプト
> bundle install

bundle installした結果👇

コマンドプロンプト
> bundle install
.
.
.
Installing faraday 2.7.10
Bundle complete! 19 Gemfile dependencies, 82 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

次に、pokeコントローラを作ります。
コントローラを作成する場合、複数形にすることを忘れないようにしてください。

terminal
$ rails g controller pokes index new 

これにより、下記のファイルが作成されます。

app/controllers/pokes_controller.rb
class PokesController < ApplicationController
  def index
  end

  def new
  end
end

次にルーティングを設定します。
今あるget 'pokes/index'get 'pokes/new'を削除して
config/routes.rbにコードを追加しましょう。

config/routes.rb
Rails.application.routes.draw do
  # ここから追加する
  root 'pokes#index'
  resources :pokes, :only => [:destroy]
  get 'pokes', to: 'pokes#index', as:'pokes_index'
  get 'pokes/new', to: 'pokes#new'
  post 'pokes', to: 'pokes#create'
  # ここまで
  # 以下略
end

2. ポケモンを検索する

いろいろなポケモンをゲットするために、検索できるようにします。
app/views/sharedフォルダを新たに作成し、その中に_search.html.erbを作成し、
下記のコードを書いた上で保存してください。

app/views/shared/_search.html.erb
<div style="margin-bottom: 50px;">
  <%= form_with url: path, method: :get, local: true do |form| %>
    <%= form.text_field :search %>
    <%= form.submit '検索', name: nil %>
  <% end %>
</div>

ファイル名の前に_(アンダースコア)があるファイルは部分テンプレートといい、
複数のビューファイルの共通部分として作成されるファイルのことです。
【Rails】 部分テンプレートの使い方を徹底解説!

form_withを使って、探したいポケモンをURLパラメータで送ります。
app/views/pokes/new.html.erbを以下のコードに置き換えてください。

app/views/pokes/new.html.erb
<h1 class="title">ポケモンゲットだぜ!</h1>
<!-- 追加 -->
<%= render "shared/search", { path: pokes_new_path } %>
<div>
  <% if @response.present? %>
    <table>
      <tr>
        <td>No.</td>
        <td><%= @response["id"] %></td>
      </tr>
      <tr>
        <td>Name:</td>
        <td><%= @response["name"] %></td>
      </tr>
    </table>
    <%= image_tag(@response["sprites"]["front_default"], size: "200") %>
  <% else %>
    <p>検索してね!</p>
  <% end %>
</div>

送られてきたパラメータをリクエスト先のURLに入れます。
また、リクエストが失敗した時の処理も追加します。

app/controllers/pokes_controller.rb
class PokesController < ApplicationController
  def index
  end

  def new
    # ここから追加
    return if params[:search].blank?
    raw_response = Faraday.get "https://pokeapi.co/api/v2/pokemon/#{params[:search]}"
    if raw_response.status == 200
      @response = JSON.parse(raw_response.body)
      # JSON.parseをすることで、json形式の文字列をRubyオブジェクトに変換することができる。
    else
      redirect_to pokes_new_path, notice: "#{raw_response.status}エラー!"
    end
    # ここまで追加
  end
end

フラッシュメッセージは別のページなどでも共通して利用される場合があるので、layouts/application.html.erb
に記述しておき、 逐次読み込むようにします。

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>PokemonZukan</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %>
  </head>

  <body>
    # ここから追加
    <% if flash[:notice] %>
      <div><%= flash[:notice] %></div>
    <% end %>
    # ここまで追加
    <%= yield %>
  </body>
</html>
    

Railsサーバーを起動しなおして、localhost:3000/pokes/newにアクセスしてください。
これでポケモンの検索ができるようになりました。

poke_search.gif

3.ポケモンを保存する

ポケモンのデータを保存するためにモデルとテーブルを作成します。

terminal
$ rails g model poke order:integer name:string image_url:string

orderは図鑑番号のことです。

生成されたmigrationファイルを開いて、各カラムにnull: false(NOT NULL制約という。null: falseの前にコンマをつけるの忘れずに)を追加して、rails db:migrateをします。

NOT NULL制約とは
null: falseを入れると、指定したカラムに空の状態で保存させるのを防ぎます。
migrationファイル内のnull: falseとは

db/migrate/作成日時_create_pokes.rb
class CreatePokes < ActiveRecord::Migration[5.2]
  def change
    create_table :pokes do |t|
      t.integer :order, null: false
      t.string :name, null: false
      t.string :image_url, null: false

      t.timestamps
    end
  end
end
terminal
$ rails db:migrate

 
次に空の値が保存されないように、Pokeモデルにバリデーションをかけます。

poke.rb
class Poke < ApplicationRecord
  # 以下の3行を追加
  validates :order, presence: true
  validates :name, presence: true
  validates :image_url, presence: true
  # ここまで追加する
end

コントローラーのnewアクションに変更を加えていきます。

pokes_controller.rb
class PokesController < ApplicationController
  def index
  end

  def new
    # ここから変更する
    return if params[:search].blank?

    raw_response = Faraday.get "https://pokeapi.co/api/v2/pokemon/#{params[:search]}"
    if raw_response.status == 200
      response = JSON.parse(raw_response.body)
      # Pokeインスタンスを生成するようにします。
      @poke = Poke.new(order: response["id"], name: response["name"], image_url: response["sprites"]["front_default"])
    else
      redirect_to pokes_new_path, notice: "#{raw_response.status}エラー!"
    end
    # ここまで
  end
end

 
poke/new.html.erbで、form_withを使って、検索したポケモンを保存(ポケモンゲットだぜ!)できるようにします。

poke/new.html.erb
<h1>Pokemon</h1>
<%= render "shared/search", { path: pokes_new_path } %>
<div>
  <% if @poke.present? %>
    <table>
      <tr>
        <td>No.</td>
        <td><%= @poke.order %></td>
      </tr>
      <tr>
        <td>Name:</td>
        <td><%= @poke.name %></td>
      </tr>
    </table>
    <%= image_tag(@poke.image_url, size: "200") %>
    
    <% if Poke.exists?(name: params[:search]) %>
      <%= form_with model: @poke, local: true do |f| %>
        <%= f.hidden_field :order  %>
        <%= f.hidden_field :name %>
        <%= f.hidden_field :image_url %>
        <%= f.submit 'ゲット', name: nil %>
      <% end %>
    <% else %>
      <p>すでに手持ちにいます</p>
    <% end %>
  <% else %>
    <p>検索してね!</p>
  <% end %>
</div>

 
次にapp/controllers/pokes_controller.rbcreateアクションを追加します。送られてきたパラメータを処理して、レコードに保存できるようにします。

pokes_controller.rb
  def create
    @poke = Poke.new(poke_params)

    if @poke.save
      redirect_to pokes_path, notice: "「#{@poke.name}」をゲットしました。"
    else
      render :new
    end
  end

  private

  def poke_params
    params.require(:poke).permit(:order, :name, :image_url)
  end

pokes/index.html.erbにレコードに保存されているポケモンを表示できるようにします。

pokes_controller.rb
def index
  @pokes = Poke.all
end

app/views/pokes/index.html.erbを編集します。

pokes/index.html.erb
<h1>Pokemon</h1>
<%= render "shared/search", { path: pokes_new_path } %>
<div>
  <% if @poke.present? %>
    <% @pokes.each do |poke| %>
      <div style="display: inline-block;">
        No. <%= poke.order %>,
        Name: <%= poke.name %>
        <div>
          <%= image_tag(poke.image_url, size: "200") %>
        </div>
      </div>
    <% end %>
  <% end %>
</div>

 
また、バリデーションエラーが起きた場合に、エラーメッセージを表示できるようにします。

pokes/new.html.erb
<h1>Pokemon</h1>
<%= render "shared/search", { path: pokes_new_path } %>
<div>
  <% if @poke.present? %>
    <!-- 追加 -->
    <%= render "shared/error_messages", { object: @poke } %>
    <table>
      <tr>
        <td>No.</td>
        <td><%= @poke.order %></td>
      </tr>
      <tr>
        <td>Name:</td>
        <td><%= @poke.name %></td>
      </tr>
    </table>
    <%= image_tag(@poke.image_url, size: "200") %>

    <% if Poke.exists?(name: params[:search]) %>
      <%= form_with model: @poke, local: true do |f| %>
        <%= f.hidden_field :order  %>
        <%= f.hidden_field :name %>
        <%= f.hidden_field :image_url %>
        <%= f.submit 'ゲット', name: nil %>
      <% end %>
    <% else %>
      <p>すでに手持ちにいます</p>
    <% end %>
  <% else %>
    <p>検索してね!</p>
  <% end %>
</div>
> touch app/views/shared/_error_messages.html.erb
shared/_error_messages.html.erb
<% if object.errors.present? %>
  <ul>
    <% object.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>

poke.gif

課題

逃がす機能

destroyを使用してゲットしたポケモンを逃しましょう。
削除機能を参考にしてみましょう。

リンクは

<%= button_to '逃がす', pokes_path(poke.id),method: :delete %><br>

を使いましょう。
登録したポケモン一覧に逃がすポタンがあり、それを押すと、一覧ページが消えれ(逃せ)ばOKです。

名前を変える機能

上記の記事を参考にしてください。

edit.html.erbは先程作ったnew.html.erbを少しアレンジします。

edit.html.erb
<h1>ポケモン編集</h1>
<!-- 省略 -->

    <%= form_with model: @poke, local: true do |f| %>
      <%= f.text_field :name %>
      <%= f.submit '名前を変更する', name: nil %>
    <% end %>
  <% else %>
  <% end %>
</div>
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?