[memo]ActiveHash

#ActiveHash の使い方 まとめ

**Active_Hash**とは、、、
都道府県名などの変更されないデータを「モデルファイル内」に直接記述することで、
データベースへ保存せずにデータを取り扱うことができる **Gem** のこと。

###ActiveHash導入方法

Gemfileを編集

```ruby:Gemfile
gem 'active_hash'
```
記述したら``bundle install``を実行


####例　ArticleモデルでActiveHashを導入
記事を管理するArticleモデル
記事のジャンルを管理するGenreモデル
記事のジャンルは変更されないデータ＝ActiveHashを用いて管理
<br>

#####①それぞれのモデルを作成

```ruby
rails g model article
rails g model genre --skip-migration
```
--skip-migrationとは？？
モデルファイルを作成するときに、マイグレーションファイルの生成を行わないためのオプション。今回、記事のジャンルの情報はデータベースに保存しない＝マイグレーションファイルを作成する必要はない。
<br>

#####②genreモデルでクラスを定義し、ActiveHash::Base を継承するための記述を行う
ジャンルのデータは、配列にハッシュ形式で格納

```ruby:models/genre.rb
class Genre < ActiveHash::Base
 self.data = [
   { id: 1, name: '--' },
   { id: 2, name: '経済' },
   { id: 3, name: '政治' },
   { id: 4, name: '地域' },
   { id: 5, name: '国際' },
   { id: 6, name: 'IT' },
   { id: 7, name: 'エンタメ' },
   { id: 8, name: 'スポーツ' },
   { id: 9, name: 'グルメ' },
   { id: 10, name: 'その他' }
 ]
 end
```

#####③①で生成されたarticleのマイグレーションファイルを編集・マイグレートする
以下の様に編集し　⇨　 ``rails db:migrate``
Articlesテーブルの中にgenre_idという名前のカラムを作成しているのは、投稿した記事を表示する際に、その記事に紐付いたジャンルを取得するため
Articleテーブルの中で、Genreモデル（ActiveHash）のidを外部キーとして管理することで、その記事に紐付いたジャンルの取得が実現

```ruby:db/migrate/20XXXXXXXXXXXX_create_articles.rb
class CreateArticles < ActiveRecord::Migration[6.0]
 def change
   create_table :articles do |t|
     t.string     :title        , null: false
     t.text       :text         , null: false
     t.integer    :genre_id     , null: false
     t.timestamps
   end
 end
end
```

#####④モデル間でのアソシエーションの設定
ActiveHashを用いてアソシエーションを設定する場合は、ActiveHashで定義されているmoduleをモデルに取り込む必要がある。

１）ActiveHashを導入したい（される）モデル
投稿する記事＝Articleは、1つのジャンル＝Genreに紐付いています。そのため、Articleモデルに``belongs_to``を設定します。
ActiveHashを用いて、belongs_toを設定するには、
``extend ActiveHash::Associations::ActiveRecordExtensions``と記述してmoduleを取り込みます。

```ruby:app/models/article.rb
class Article < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :genre
end
```

２）ActiveHashを設定したモデル
1つのジャンル＝Genreは、たくさんの投稿物＝Articlesに紐付いています。そのため、Genreモデルには``has_many``を設定します。

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

```ruby:app/models/genre.rb
class Genre < ActiveHash::Base
 self.data = [
   { id: 1, name: '--' },
  〜〜〜省略〜〜〜
   { id: 10, name: 'その他' }
 ]

  include ActiveHash::Associations
  has_many :articles

 end
```

※moduleとは、特定の役割を持つメソッドや定数に名前を付けてまとめたもの。どのようなmoduleが定義されているかは、[こちらのリファレンス](https://github.com/zilkey/active_hash/blob/master/lib/associations/associations.rb)で確認。

※ActiveHashを用いたアソシエーションの設定は、他にもあります。詳しくは[こちらのドキュメント](https://github.com/zilkey/active_hash)を確認。
<br>

#####⑤バリデーションを設定
データベースに空の投稿が保存されないようにする場合、バリデーションヘルパーの``numericality（数値かどうかを検証する）``を用いる。数値であればデータベースに保存を許可して、それ以外では保存が許可されないようにできます。今回においては、--を保存されないようにしたいので、id: 1以外であれば保存できるように設定すると

```ruby:app/models/article.rb
class Article < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :genre

  #空の投稿を保存できないようにする
  validates :title, :text, presence: true

  #ジャンルの選択が「--」の時は保存できないようにする
  validates :genre_id, numericality: { other_than: 1 } 
end
```

このバリデーションは、``genre_idのid:1以外のときに保存できる``という意味になる。


導入については以上です。ジャンル選択のプルダウン生成などはview関連になるため
別記事に追記予定。