[Rails6]ActiveHashについて　〜変更されないデータの取扱い方〜

## はじめに
現在未経験からのエンジニアへの転職するため、日々学習を励んでいます。　　
知識整理のためアウトプットします！　　
間違った内容などあるかもしれませんがご容赦ください！

## ActiveHashとは
一言でまとめると、「__変更されないデータをデータベースに保存することなく取り扱うことができるgem__」と理解してます！
例えば、都道府県一覧などは変更されないですよね？！　　
このようなデータを直接モデルに記入することで、データベースには保存せずともデータが取り扱えるgemです！
つまり、ActiveHashを用いることでActiverecordメソッドが使えるようになるんです！

## 導入方法

```ruby:gemfile
gem 'active_hash'
```
```ruby:ターミナル
%  bundle install
```

これで下準備は終わり。

## モデルを作成する
今回は、料理投稿アプリを想定して、foodモデルと、costモデルを作成します。

```ruby:マイグレーションファイル(foodsテーブル)
class CreateFoods < ActiveRecord::Migration[6.0]
  def change
    create_table :foods do |t|
      t.string :title,    null: false
      t.integer :cost_id, null: false
      t.timestamps
    end
  end
end
```
ここで注意！
カラム名に_idをつけ、カラムの型はinteger型にしましょう！　　

```ruby:cost.rb
class Cost < ActiveHash::Base
  self.data = [
    { id: 1, name: '100円以下' },
    { id: 2, name: '300円前後' },
    { id: 3, name: '500円前後' },
    { id: 4, name: '1,000円前後' },
    { id: 5, name: '2,000円前後' },
    { id: 6, name: '3,000円前後' },
    { id: 7, name: '5,000円前後' },
    { id: 8, name: '10,000円前後' },
  ]
end
```

cost.rbはエディタから直接ファイルを作り上記の方に記述します。

まずは、モデルの「Costクラス」を定義し、ActiveHash::Baseクラスを継承します。
ActiveHash::Baseは、あるクラス内でActiveHashを用いる際に必要となるクラスです。
ActiveHash::Baseを継承することで、ActiveRecordメソッドを使用できるようになります。

##アソシエーションの設定
投稿した料理は、1つのコストに紐付いています。そのため、Foodモデルにはbelongs_toを設定します。
この際、extend ActiveHash::Associations::ActiveRecordExtensionsと記述してmoduleを取り込みます。

```ruby:food.rb
class Food < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :cost
end
```

1つのコストは、たくさんの投稿した料理に紐付いています。そのため、Genreモデルにはhas_manyを設定します。
この際、include ActiveHash::Associationsと記述してmoduleを取り込みます。

```cost.rb
class Cost < ActiveHash::Base
  self.data = [
    { id: 1, name: '100円以下' },
    { id: 2, name: '300円前後' },
    { id: 3, name: '500円前後' },
    { id: 4, name: '1,000円前後' },
    { id: 5, name: '2,000円前後' },
    { id: 6, name: '3,000円前後' },
    { id: 7, name: '5,000円前後' },
    { id: 8, name: '10,000円前後' },
  ]

include ActiveHash::Associations #ここを追加
has_many :foods #ここを追加

end
```

##collection_selectを用いてブルダウンメニューを表示させる。

```○○○.html.erb
<%= f.collection_select(:cost_id, Cost.all, :id, :name, {}, {class:"cost-select"}) %>

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

##バリデーションを設定しよう

今回は２パターン紹介します！

### ①「numericality」というバリデーション のヘルパーを使用する方法
numericalityとは、数値かどうかを検証するバリデーションの一種です。
数値であればデータベースに保存を許可して、それ以外では保存が許可されないようにできます。

```cost.rb
class Cost < ActiveHash::Base
  self.data = [
    { id: 1, name: '---' },　#id:1に「---」を追加する。
    { id: 2, name: '100円以下' },
    { id: 3, name: '300円前後' },
    { id: 4, name: '500円前後' },
    { id: 5, name: '1,000円前後' },
    { id: 6, name: '2,000円前後' },
    { id: 7, name: '3,000円前後' },
    { id: 8, name: '5,000円前後' },
    { id: 9, name: '10,000円前後' },
  ]

include ActiveHash::Associations
has_many :foods

end
```

```food.rb
class Food < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :cost

  validates :title, presence: true

  #コストの選択が「---」の時は保存できないようにする
  validates :cost_id, numericality: { other_than: 1 } 
end
```

###②collection_selectのオプションを使用する方法
collection_selectの第五引数で設定するオプションを使用します。

```○○○.html.erb
#第五引数に{ include_blank: "---" }を記入する。
<%= f.collection_select(:cost_id, Cost.all, :id, :name, { include_blank: "---" }, {class:"cost-select"}) %>
```

include_blankをしようすることで、値のない選択肢を先頭にすることができます。
そうすることで、、、with_optionsでまとめることができる！！
ちょっと見やすいかな？

```food.rb
class Food < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :cost

  with_options presence: true do
    validates :title
    validates :cost_id
  end
end
```

##終わりに
以上になります！
間違ってたら、バシバシ言っていただけるとありがたいです！