Rails 選択ボックスの使い方 1 ー  蔵書管理アプリに「本のジャンル」を追加してみる 基本編 (select)

応用編はこちら
[Rails 選択ボックスの使い方 2 ー 蔵書管理アプリに「本のジャンル」を追加してみる 応用編 (collection_select)](https://qiita.com/majorboy/items/e21e332e64d12a26c679)

### はじめに
プログラミング学習のアウトプットとしてポートフォリオ開発に取り組む方向けの記事です。
開発初期はtext_fieldを使って「商品名」や「ユーザー名」を保存するといった簡単なCRUD機能の実装から始められる方も多いと思います。

アプリの機能拡張アイデアの一つとして、本記事では「選択ボックスの使い方」を解説します。

題材としてはscaffoldを使った簡単な蔵書管理アプリ（bookapp)を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481666/f15a1d70-d153-a9e2-8990-794c44870673.png)


ご覧のように現状では「書名」、「作者名」のみ登録できる状態です。
基本編ではselectメソッドを使って「本のジャンル」選択ボックスを追加してみます。

### 対象読者の方
Rails学習を一通り終えて、初めてポートフォリオ開発に取り組まれる方

### 目指すゴール
selectメソッドを使って蔵書管理アプリに「本のジャンル」選択ボックスを実装する

#### 完成イメージ
新規投稿フォーム(Book)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481666/61b022fc-c62c-eafd-9711-80caf150220d.png)

投稿一覧画面 (Book)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481666/9b63b8e3-c9f8-5f1e-1b7e-4e9804a2b318.png)



### 実装の流れ
#### 準備
1 アプリの雛形を作成

2 scaffoldで蔵書管理機能を一気に実装する(CRUD)

#### 基本編(select）
1 Booksテーブルにgenreカラムを追加（migration) 

2 「本のジャンル」選択ボックスを作成

3 strong parameterにgenreを追加

4 一覧画面に「本のジャンル」を表示する


### 準備１ アプリの雛形を作成
まずはターミナルで開発用のディレクトリを作成します。
ディレクトリ名は何でも構いませんが、ここでは「rails-project」としておきます。
ディレクトリ作成後は「rails-project」に移動しておいてください。

```:ターミナル
$ mkdir rails-project

$ cd rails-project

[rails-project]
```

次にアプリの雛形を作成します。
アプリ名は「bookapp」 DBはmysqlを使用します。

```:ターミナル
[rails-project] $ rails new bookapp -d mysql
```

### 準備2 scaffoldで蔵書管理機能を一気に実装する
アプリの雛形ができたらscaffoldを使って蔵書管理機能を一気に実装します。
ここでは「書名」・「作者名」のみ登録可能なCRUD機能を作っていきます。

#### 1) scaffoldで蔵書管理機能を追加（CRUD)
```:ターミナル
# bookappに移動
[rails-project] $ cd bookapp

# scaffoldで蔵書管理機能を追加（CRUD）
[bookapp] $ rails g scaffold book title:string author:string

# DB作成 & migrationを実行
[bookapp] $ rake db:create

[bookapp] $ rake db:migrate

```

[補足]

- 機能追加を体験できるように若干遠回りな進め方をしています。

- scaffold 使い方関連記事
[Rails scaffoldを初心者向けに解説！実際にアプリを作ってみよう！](https://udemy.benesse.co.jp/development/web/scaffold.html)

#### 2) トップページのルーティングを設定
トップページのルーティングはbooks#indexにしておきます。

```diff:route.rb
Rails.application.routes.draw do
+ root 'books#index'
  resources :books
end
```

#### 3) ブラウザでTopページの表示を確認 
ここまで出来たら一度サーバを起動して表示を確認しておきましょう。


```:ターミナル
[bookapp] rails s
```
[ 初期画面 ] http://localhost:3000
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481666/43b26c9b-6c67-22ca-0a25-818e0e117946.png)

[ テストデータ追加] 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481666/f15a1d70-d153-a9e2-8990-794c44870673.png)

新規登録、編集、削除も一通り動くか、確認しておくといいかもしれません。

### 基本編(select）
必要な準備が一通り完了しました。ここからは蔵書管理機能に「本のジャンル」選択ボックスを追加していきます。

### 1 Booksテーブルにgenreカラムを追加
まずは「本のジャンル」をDBに保存できるようにmigrationファイルを追加します。

```:ターミナル
[bookapp] rails g migration AddGenreToBooks genre:string
```

```ruby:migrationファイル
class AddGenreToBooks < ActiveRecord::Migration[5.2]
  def change
    add_column :books, :genre, :string
  end
end
```

ファイル作成完了したら、migrationを実行します。

```:ターミナル
[bookapp] rake db:migrate
== AddGenreToBooks: migrating ==================================
-- add_column(:books, :genre, :string)
  
== AddGenreToBooks: migrated  =========================
```
これでgenreカラムの追加は完了です。

[補足]

- カラム追加・削除関連記事（migration)  
[Railsでデータベースカラムの追加を行う方法](https://qiita.com/ryosuketter/items/1aba45161bfffefed68b)  
[Ruby on Railsでテーブルのカラムを追加・削除する方法](https://reasonable-code.com/rails-column/)

### 2 「本のジャンル」選択ボックスを作成
次は新規投稿フォームに「本のジャンル」選択ボックスを作っていきます。
現状は以下のようにtitleとauthorのみ入力できる状態です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481666/f2a74a86-2615-7046-7419-e8b18ad78249.png)

新規投稿フォームに以下を追加します。選択肢の例は適宜変更してください。

```diff:views/books/_form.html.erb

<%= form_with(model: book, local: true) do |form| %>
  <% if book.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(book.errors.count, "error") %> prohibited this book from being saved:</h2>

      <ul>
      <% book.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div class="field">
    <%= form.label :author %>
    <%= form.text_field :author %>
  </div>


+ <div class="field">
+  <%= form.label :genre %>
+  <%= form.select :genre, ['小説', 'プログラミング', 'ビジネス'], {include_blank: '---'} %>
+ </div>
```

ブラウザで確認すると以下のように選択ボックスが追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481666/7462f3bb-05fa-d379-8194-872943e1b1d5.png)


[解説]
**1) selectメソッドの使い方**
選択ボックス作成で一番シンプルに使えるのがselectメソッドです。

[構文]
**select プロパティ名(シンボル）,  選択肢(配列 or ハッシュ), {オプション}, {HTMLオプション}(id,class等）**

例：<%=　form.select　:genre, 　['小説', 'プログラミング', 'ビジネス'], 　{include_blank: '---'}　%>

**２) include_blankについて**
選択肢にブランクを入れたい場合はselectメソッドのオプションにinclude_blankを追加します。
incliude_blank:trueとすれば選択肢にブランクが追加されます。
上記例（'---'）のようにブランク用の表示テキストを指定することも可能です。

**3) 選択肢(配列 or ハッシュ)の違いについて**
選択肢は配列orハッシュで定義できます。配列の場合、フォームのvalue属性が文字列になります。
DBにも文字列型(string)として保存されます。

```:HTML表示（配列の場合）
['小説', 'プログラミング', 'ビジネス']
=>
<select name="book[genre]" id="book_genre"><option value="">---</option>
  <option value="小説">小説</option>
  <option value="プログラミング">プログラミング</option>
  <option value="ビジネス">ビジネス</option>
</select>
```

一方で「選択肢は文字で表示したい、でもDB保存は数値で行いたい」というケースもあります。
その場合、選択肢をハッシュで定義すれば、DBに保存するvalue属性を数値(integer)にできます。

```:HTML表示（ハッシュの場合）
{'小説' => 1, 'プログラミング' => 2, 'ビジネス' =>3}
=>
<select name="book[genre]" id="book_genre">
  <option value="">---</option>
  <option value="1">小説</option>
  <option value="2">プログラミング</option>
  <option value="3">ビジネス</option>
</select>
```

### 3 strong parameterにgenreを追加
新たに追加した「本のジャンル」をDB保存できるようにcontrollerを編集します。
strong parameterに:genreを追加します。

```diff:books_controller.rb
private

（省略）

def book_params
-   params.require(:book).permit(:title, :author)
+   params.require(:book).permit(:title, :author, :genre)
end
```

### 4 一覧画面に「本のジャンル」を表示する

最後に一覧画面で「本のジャンル」表示欄を追加しましょう。

```diff:views/books/index.html.erb

<p id="notice"><%= notice %></p>

<h1>Books</h1>

<table>
  <thead>
  <tr>
    <th>Title</th>
    <th>Author</th>
+   <th>Genre</th>
     <th colspan="3"></th>
   </tr>
  </thead>

  <tbody>
    <% @books.each do |book| %>
      <tr>
        <td><%= book.title %></td>
        <td><%= book.author %></td>
+       <td><%= book.genre %></td>
        <td><%= link_to 'Show', book %></td>
        <td><%= link_to 'Edit', edit_book_path(book) %></td>
        <td><%= link_to 'Destroy', book, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
 </table>

<br>

<%= link_to 'New Book', new_book_path %>
```

ここまで出来たらブラウザに接続して本のジャンル登録＆一覧画面での表示ができるか確認します。

http://localhost:3000/


以下例のように一覧画面で本のジャンルの表示ができれば基本編は完成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481666/cafd4b6b-bc7b-8698-e955-85d65208fa4a.png)

応用編はこちら
[Rails 選択ボックスの使い方 2 ー 蔵書管理アプリに「本のジャンル」を追加してみる 応用編 (collection_select)](https://qiita.com/majorboy/items/e21e332e64d12a26c679)

###関連記事
- [【Rails/選択ボックス】selectを使って選択ボックスを作る方法](https://shinmedia20.com/rails-select-box)

- [【Rails】完全理解 formでセレクトボックスをつくるselectの使い方](https://310nae.com/rails-selectbox/)
- [railsでf.selectにclassを設定する](https://qiita.com/nakanoyoshiki/items/e87a6238f8febbeb208a)