Railsでactive_hashを使って都道府県などのセレクトボックスを作る

# はじめに
・某プログラミングスクールのチーム開発で学んだ知識の備忘録として書きます。
・商品がどの都道府県から発送されるのか、という情報のために使用しました。
・間違いなどあれば指摘いただけますと幸いです。

# active_hashって何？
・`ハッシュデータとして定義したデータを、擬似的にActiveRecordのように扱う`ことができるのが`active_hash`というgem。
・都道府県など、`項目数がほぼ変わらない静的データ`はテーブルにせず、active_hashを使うと便利。
・ActiveRecord <=> ActiveHashの`リレーションを張ることができる`。

# 使い方
順を追って書いていきます。

```ruby:Gemfile
# ファイルの一番下に記述追加。haml記法で記述するのでhaml-railsも入れます
gem 'active_hash'
gem 'haml-rails'
```
```terminal:ターミナル
$ bundle install
```
これでactive_hashがインストールされました。
ミニアプリを作ってみます。

```terminal:ターミナル
$ rails g model item name:string　prefecture_id:integer
```
`models/items.rb`
`db/migrate/20200817033056_create_items.rb`
が作成されました。


```ruby:20200817033056_create_items.rb
class CreateItems < ActiveRecord::Migration[6.0]
  def change
    create_table :items do |t|
      t.string :name
      t.integer :prefecture_id

      t.timestamps
    end
  end
end
```

```terminal:ターミナル
$ rails db:migrate
```
これでitemsテーブルができました。

### ここ大事です
prefectureモデルを作るのですが、手動で作ります。
`rails g model`はしません。

modelsディレクトリに`prefecture.rb`ファイルを直接作成します。
作成したら中身を以下のように記述します。

```ruby:prefecture.rb
class Prefecture < ActiveHash::Base
  self.data = [
      {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'},
      {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'},
      {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'},
      {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'},
      {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'},
      {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'},
      {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'},
      {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'},
      {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'},
      {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'},
      {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'},
      {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'},
      {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'},
      {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'},
      {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'},
      {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]

  include ActiveHash::Associations
  has_many :items
end
```
itemモデルにも記述を追加します。

```ruby:item.rb
class Item < ApplicationRecord
  # この2行を追加
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :prefecture

end
```
準備は以上です。
ちゃんと表示できて、データ送信もできたら完成とします。
コントローラーとビューを作ってルーティングも設定します。

```terminal:ターミナル
$ rails g controller items new
```

```ruby:items_controller.rb
class ItemsController < ApplicationController
  def new
    @item = Item.new
  end
  def create
    @item = Item.new(item_params)
    if @item.save
      redirect_to new_item_path
    else
      render 'new'
    end
  end
  
  private

  def item_params
    params.require(:item).permit(:name, :prefecture_id)
  end
end
```


```ruby:items/new.html.haml
.form
  = form_with model: @item, local: true do |f|
    = f.text_field :name  # 入力フィールドです
    = f.collection_select :prefecture_id, Prefecture.all, :id, :name, {include_blank: "---"}, {class: ""}
    = f.submit "送信"
```
都道府県はf.collection_selectを使ってセレクトボックス形式で取得します。
`= f.collection_select 保存されるカラム名, オブジェクトの配列, カラムに保存される項目, 選択肢に表示されるカラム名, {オプション}, {htmlオプション}`

```ruby:routes.rb
Rails.application.routes.draw do
  resources :items
  root 'items#new'
end
```

入力フィールドとセレクトボックスを埋めて送信したら入力画面に戻るようにしています。
成功したら入力フィールドが空になります。
sequelproなどのGUIツールでテーブルの中身を見るとデータが保存されているはずです。

# 都道府県だけじゃなくこんなのにも使えます
・商品の状態

```ruby:models/item_condition.rb
class ItemCondition < ActiveHash::Base

  self.data = [
    {id: 1, condition: '新品、未使用'}, {id: 2, condition: '未使用に近い'}, {id: 3, condition: '目立った傷や汚れなし'},
    {id: 4, condition: 'やや傷や汚れあり'}, {id: 5, condition: '傷や汚れあり'}, {id: 6, condition: '全体的に状態が悪い'}
  ]

  include ActiveHash::Associations
  has_many :items

end
```
この場合、f.collection_selectはこんな感じです。

```ruby:items/new.html.haml
= f.collection_select :item_condition_id, ItemCondition.all, :id, :condition, {include_blank: "選択してください"}, {class: "select"}
```
第5引数にはデフォルトで表示させたい文字列を、
第6引数にはクラス名やid名を指定します。

# まとめ
ミニアプリを作ったので少し長くなりましたが、active_hashを実装するだけなら以下の手順です。
1.gemをインストール
2.カラム作成（itemsテーブルに`prefecture_idカラムをinteger型で作成`）
3.モデルファイル作成してテーブルにあたる記述を追加（`prefecture.rb`）
4.Itemモデル側にアソシエーションを記述。通常とは違うので注意

以上です。
今回active_hashのメソッドとして全部のデータを取得するために`allメソッド`を使いましたが、他にも色々あります。
参考サイトを載せるので必要であればそちらから見てください。

# 参考
【Rails】active_hashを使って疑似モデルを作ろう
https://pikawaka.com/rails/active_hash
active_hashまとめ
https://qiita.com/Toman1223/items/8633142312bfa886d50b