【Rails】プルダウンリストの実装（ActiveHash）

# 目的
Railsで作成したアプリにプルダウンリストを追加する。

# 開発環境
macOS: *Big Sur*
Rubyバージョン: *2.6.5*
Railsバージョン: *6.0.0*

# 前提
- アプリを立ち上げ済み。

# 手順

1. [前置き](#前置き)
1. [ActiveHashのインストール](#activehashのインストール)
1. [モデルの作成](#モデルの作成)
1. [マイグレーションファイルの編集](#マイグレーションファイルの編集)
1. [アソシエーションの追加](#アソシエーションの追加)
1. [バリデーションの設定](#バリデーションの設定)
1. [プルダウンリストの表示](#プルダウンリストの表示)

# 前置き

都道府県名一覧などの`「基本的に変更されないデータ」`は、データベースに保存する必要性がありません。
また、ビューファイルに直接書く方法もありますが可読性に欠けてしまいます。
そのようなケースでは、`ActiveHash`が有用です。

`Active_Hash`とは、モデルファイル内に直接記述したデータを、データベースへ保存することなく取り扱うことができるGemの事です。
これを用いることで、モデルファイル内に記述したデータに対して、ActiveRecordのようなメソッド（allやcreateメソッド）を用いることができます。

今回は商品（Item）と商品がどこにあるか（Prefecture）という関係があった場合を仮定し、進めていきます。
内容としては、プルダウンリストで都道府県が選択できるところまでを記載します。
細かいビューなどは省略しますので、各自編集をお願いします。

# ActiveHashのインストール

それでは早速始めていきましょう！
ますActiveHashをインストールします。

```ruby:Gemfile
#省略
gem 'active_hash'
```

```:ターミナル
bundle install
```

# モデルの作成

今回のアプリでは、商品を管理するItemモデルと、商品の場所（都道府県）を管理するPrefectureモデルを作成します。
都道府県を管理するモデルは、ActiveHashを用いて管理していきます！

まず下記コマンドを実行して、Itemモデルを作成します！

```:ターミナル
% rails g model item
```
続いて、app/modelsディレクトリ配下に`prefecture.rb`を手動で作成します。

### Prefectureモデルへデータを定義

次にプルダウンリストの作成です！

ここで少し説明ですが、モデルの「Prefectureクラス」を定義し、`ActiveHash::Base`クラスを継承する必要があります。
`ActiveHash::Base`とは、ActiveHashを用いる際に必要となるクラスです。
このクラスを継承することで、ActiveRecordと同じようなメソッドを使用できるようになります！

本題に戻って、以下のようにプルダウンリストを作成していきましょう！

```ruby:app/models/prefecture.rb
class Prefecture < ActiveHash::Base
 self.data = [
   { id: 1, name: '--' },
   { id: 2, name: '北海道' },
   { id: 3, name: '青森県' },
   { id: 4, name: '岩手県' },
   { id: 5, name: '宮城県' },
#中略
 ]
 end
```

この記述で、Prefectureモデルに`ActiveHash::Base`を継承することができ、
都道府県のデータに対して、ActiveRecordのようなメソッドが使用できるようになりました！

# マイグレーションファイルの編集
続いてマイグレーションファイルの編集です。

```ruby:db/migrate/20XXXXXXXXXXXX_create_items.rb
class CreateItems < ActiveRecord::Migration[6.0]
 def change
   create_table :items do |t|
     t.string     :title        , null: false
     t.text       :text         , null: false
     t.integer    :prefecture_id     , null: false
     t.timestamps
   end
 end
end
```

今回は商品に紐付く都道府県を表示させる方法も紹介します。
そのために`prefecture_id`という名前のカラムを作成します。

編集後は下記コマンドでデータベースに反映しましょう！

```:ターミナル
% rails db:migrate
```

# アソシエーションの追加

商品と紐付いた都道府県を取得できるように、ItemモデルとPrefectureモデル間でアソシエーションを設定しておきます！
ActiveHashを用いてアソシエーションを設定する場合は、ActiveHashで定義されている`module`をモデルに取り込む必要があります。
`module`とは、特定の役割を持つメソッドや定数に名前を付けてまとめたものです。

では、実際にActiveHashを用いたアソシエーションを設定していきましょう！

### Itemモデルのアソシエーションを設定

商品は1つの都道府県に紐付いています。そのため、Itemモデルにはbelongs_toを設定します。

ActiveHashを用いて、belongs_toを設定するには、
`extend ActiveHash::Associations::ActiveRecordExtensions`と記述してmoduleを取り込みます!

```ruby:app/models/item.rb
class Item < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :prefecture
end
```
これで、ActiveHashを用いてのbelongs_toが設定できました!

### Prefectureモデルのアソシエーションを設定

続いて都道府県です！
1つの都道府県はたくさんの商品に紐付いています。そのため、Prefectureモデルにはhas_manyを設定します。

ActiveHashを用いて、has_manyを設定するには、
`include ActiveHash::Associations`と記述してmoduleを取り込みます！

```ruby:app/models/prefecture.rb
class Prefecture < ActiveHash::Base
 self.data = [
   { id: 1, name: '--' },
   { id: 2, name: '北海道' },
   { id: 3, name: '青森県' },
   { id: 4, name: '岩手県' },
   { id: 5, name: '宮城県' },
#中略
 ]

  include ActiveHash::Associations
  has_many :items

 end
```

以上でアソシエーションを設定できました！

# バリデーションの設定

次にバリデーションの設定をしていきます！

プルダウンリストのカラム型は`integer`なので、`numericality`を使い設定してきます！

```ruby:app/models/item.rb
class Item < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :prefecture

  #中略

  #都道府県の選択が「--」の時は保存できないようにする
  validates :prefecture_id, numericality: { other_than: 1 } 
end
```

これで、`「数値であること」＆「id: 1以外」`という条件での保存が許可されるバリデーションが設定できました！
「id: 1以外」という条件は都道府県のid1が`「--」`という何も選択していないという意味だからです。

# プルダウンリストの表示

最後にプルダウンリストの表示の仕方を記述します！
以下のような記述で表示が可能です！

```:例
<%= form.collection_select(保存されるカラム名, オブジェクトの配列, カラムに保存される項目, 選択肢に表示されるカラム名, オプション, htmlオプション) %>
```

| 引数                  | 値                          | 役割                  |
| -------------------- | --------------------------- | -------------------- |
| 保存されるカラム名       | :prefecture_id              | 保存先のカラム名         |
| オブジェクトの配列        | Prefecture                  | 配列データの指定        |
| カラムに保存される項目    | id                          | 参照するDBのカラム名      |
| 選択肢に表示されるカラム名 | name                        | 実際に表示されるカラム名   |
| オプション              | {}                          | 今回は指定なし          |
| htmlオプション          | {class:"prefecture-select"} | 今回はCSSのクラス名を付与 |


```:app/views/items/new.html.erb
<%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"prefecture-select"}) %>
```

今回の場合ですとこのように記述することで実装出来ます！

# 最後に

以上で、プルダウンリストの実装ができたと思います。
あとは各自、ルーティングの設定やビューファイルの編集などしてください。
では。