Railsでポケモン図鑑を作ろう 課題

## はじめに
本記事は[Railsでポケモン図鑑を作ろう](https://qiita.com/earth660/items/160c0ee8ae4f836e9fd7)で作成したアプリケーションに課題として機能を追加していきます。様々なヒントややり方を載せていますので参考にしてチャレンジしてください。


## 1. 編集機能
投稿したものの内容を変更できる機能があると便利です。
ポケモンの情報を編集できる機能を実装していきましょう。

### 1.1 routes・controllers・view の3点に、編集ページを新規作成する

まずはconfig/routes.rbを編集します。
```rb:config/routes.rb
Rails.application.routes.draw do
  get 'pokemons/index'
  get 'pokemons/show/:id', to:'pokemons#show', as: 'pokemon'
  get 'pokemons/new'
  post 'pokemons', to: 'pokemons#create'
  # 以下の2行を追加
  get 'pokemons/:id/edit', to: 'pokemons#edit', as: 'edit_pokemon'  
  patch 'pokemons/:id/', to: 'pokemons#update'
  # ここまで
end
```

::: note
データを更新するアクションは、HTTPメソッドの「**PATCH**」または「**PUT**」を使用します。
patchとputのどちらを使うか迷った場合は、Railsで推奨されている**patch**を使用しましょう。

as:オプションを使うとルーティングに名前を指定できます。
上記だと、名前付きヘルパーとして`edit_pokemon_path`と`edit_pokemon_url`が作成されます。
`edit_pokemon_path`を呼び出すと`pokemons/:id/edit`が返されます。
:::


次に`pokemons_controller.rb`のcreateアクションの下に**edit**アクションを作成します。
```rb:ap/controllers/pokemons_controller.rb
def create
    # 省略
end

# 下の3行を追加
def edit
  @pokemon = Pokemon.find(params[:id])
end
# ここまで
```

::: note
アクション名は「edit」です。
編集ページで必要な情報は、「一つのpokemon」です。
よって、今回は「params[:id]」で、一つだけidを取得します
これはshowアクションと同様のことを行っています。
:::


次にビューを作成します。
コマンドプロンプトで下のコマンドを実行すると、`edit.html.erb`が生成します。
（エディタから新規ファイルを作成からでも構いません）

app/views/pokemons/edit.html.erbは下記のようにしましょう。
<details><summary>コードはこちら(クリックしてください)</summary>

```erb:app/views/pokemons/edit.html.erb
<div class="container mt-6">
  <div class="columns">
    <div class="column is-three-fifths is-offset-one-fifth">
      <%= form_with model:@pokemon, url:"/pokemons/#{@pokemon.id}", local:true do |f| %>
        <!-- 	エラーメッセージ	 -->
        <% if @pokemon.errors %>
          <% @pokemon.errors.full_messages.each do |message| %>
		    <div class='alert'>
		      <ul>
          　　   <li><%= message %></li>
			  </ul>
			</div>
          <% end %>
      　<% end %>
		<!-- 	ここまでエラーメッセージ	 -->
        <div class="field">
          <%= f.label :name, "なまえ", class: 'label'%>
          <div class="control">
            <%= f.text_field :name, class:'input'%>
          </div>
        </div>
		
        <div class="field">
          <%= f.label :number, "ばんごう", class: 'label' %>
          <div class="control">
            <%= f.text_field :number, class: 'input'%>
          </div>
        </div>
		
        <div class='field'>
          <%= f.label :zokusei, "タイプ", class: 'label' %>
          <div class="control">
            <%= f.text_field :zokusei, class: 'input'%>
          </div>
        </div>
		
        <div class="field">
          <%= f.label :description, "せつめい", class: 'label' %>
          <div class="control">
            <%= f.text_area :description, class: 'textarea' %> 
          </div>       
        </div>
		

		
		
        
        <div class="file">
          <label class="file-label"></label>
        </div>
        <br/>
        <br/>
        <div class="file is-boxed">
            <label class="file-label">
            <%= f.file_field :image, class: 'file-input'%>
              <span class="file-cta">
                  <span class="file-icon">
                      <i class="fas fa-upload"></i>
                  </span>
                  <span class="file-label">
                    <%= f.label :image, 'がぞう', class: 'label'%>
                  </span>
             </span>
          </label>
        </div>
        
        <%= f.submit "登録", class: 'button is-link'%>
      <% end %>
    </div>
  </div>
</div>
```
</details>


::: note
form_withでモデルにインスタンス変数を渡すことで(model:@pokemon)、編集したいポケモンの情報が既にフォーム内に入っています。
フォームはnew.html.erbのときとほとんど同じです。
:::


そして、再びコントローラにコードを追加していきます。
app/controllers/pokemons_controller.rbの**edit**アクションに**update**アクションを追加します。

```rb:app/controllers/pokemons_controller.rb
def edit
  @pokemon = Pokemon.find(params[:id]
end

# ここから追加する
def update
  pokemon = Pokemon.find(params[:id])
  pokemon.update(pokemon_params)
  redirect_to pokemon_path(pokemon.id) 
  #  ↑ ポケモンのshowページに移動する
  end
	
  private
  
  def pokemon_params
    params.require(:pokemon).permit(:name, :zokusei, :number, :description, :image)
  end
# ここまで追加する
```

最後にポケモン詳細ページに編集ページのリンクを貼りましょう。
```erb:app/views/pokemons/show.html.erb
(中略)
<div class="column is-8">
  <div class="p-description">
    <%= @pokemon.description %>
  </div>
  <p class="p-edit"> <%= link_to 'へんしゅう', edit_pokemon_path, class: 'button is-info'%> </p> 
　　　　<!--　上の１行を追加する　-->
（中略）
</div>
```

## ポケモン検索機能
検索機能には色々とありますが、ポケモン名を完全一致で検索できるものを作っていきます。

##### 1.検索フォームを作成する
既存にあるindex.html.erbの上部に検索フォームを追加します。
new.html.erbやedit.html.erbとほとんど似ていますが、
`:search`など、検索に関わるカラムを追加しています。
```erb:app/views/app/pokemons/index.html.erb
<!-- ここから -->
  <div class="field has-addons">
  <div class="control">
     <%= form_with(url: pokemons_index_path, class: 'search_form', method: :get, local:true) do |f| %>
     <%= f.text_field :search, class:'field', value: params[:search], placeholder: "ポケモンけんさく", class: 'input'%>
  </div>
  <div class="control">
    <%= f.submit 'けんさく', class: "button is-info" %>
    <% end %>
  </div>
</div>
<!-- ここまで　-->

<div class="container mt-6">
  <h1 class="title has-text-centered"> ポケモンいちらん </h1>
  <!-- 省略　-->
</div>
```

##### 2.コントローラーの編集
pokemon_controller.rbのindexアクションを以下に書き換えましょう。
indexアクション内１行目の`@pokemons = Pokemon.all`は一覧ページが表示されたときは登録しているポケモンすべてを表示するようにしており、
indexアクション２行目の`@pokemons = params[:search].present? ? Pokemon.pokemon_serach(params[:search]) :  Pokemon.all`は検索フォームに入力されたものがPokemonモデルにあるかどうかを判定し、存在していれば、`@pokemons`にいれ、表示をします。存在していなかったら、ポケモンすべてを表示します。
```ruby:app/controllers/pokemon_controller.rb
class PokemonsController < ApplicationController
  def index
    @pokemons = params[:search].present? ? Pokemon.pokemon_serach(params[:search]) :  Pokemon.all
  end
```

##### 3.モデルの編集
検索機能の詳しい実装はモデル内でしていきましょう。
```diff_ruby:app/models/pokemon.rb
class Pokemon < ApplicationRecord
  (省略)
  
  def self.pokemon_serach(search)
    Pokemon.where(['name LIKE ?', "%#{search}%"])
  end
end
```
ポケモンいちらんページで名前を検索（カタカナで）すると
一致したポケモンのみ表示されます。


詳しく知りたい人は以下のサイトを参考にしてください。

https://qiita.com/E6YOteYPzmFGfOD/items/dc1ab3c19d4718a0edc8