【Rails】ActiveHash(Gem)について

# 記事概要
Ruby on RailsのActiveHash(Gem)について、まとめる

# 前提
- Ruby on Railsでアプリケーションを作成している
- ActiveHashを用いて実装する「クラス」を、便宜上「モデル」と呼称する

# サンプルアプリ(GitHub)
https://github.com/likapantrip/active_hash_app

# ActiveHashとは
変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるGem

https://github.com/active-hash/active_hash

## ActiveHash::Base
あるモデル内(クラス内)でActiveHashを用いる際に必要となるクラス
ActiveHashのGemに定義されており、`ActiveHash::Base`を継承することで、ActiveRecordと同じようなメソッドを使用できる

# Gemのインストール手順
https://qiita.com/likapantrip/items/d7317b9ece36b58dffd6#手順

# Gemfileの記述
https://qiita.com/likapantrip/items/c8718db9a4e72b7c6ad0#activehash

# 手順①(モデルの作成)
1. ActiveHashを利用するモデルを作成済みの場合は、手順②へ進む
1. モデルを作成する
    ```
    % rails g model [モデル名]
    ```
1. マイグレーションファイルを編集する
    ```db/migrate/20XXXXXXXXXXXX_create_articles.rb
    class CreateArticles < ActiveRecord::Migration[7.0]
     def change
       create_table :articles do |t|
         t.string     :title        , null: false
         t.text       :text
         
         # カラム名は、[ActiveHashのモデル名]_id
         # カラム型は、integer
         t.integer    :genre_id     , null: false
         t.timestamps
       end
     end
    end
    ```
    ※ActiveHashを紐づけるテーブルの中で、ActiveHashのモデルのidを外部キーとして管理することで、テーブルデータに紐付いたジャンルの取得が実現できる
1. マイグレーションを実行し、テーブルを作成する

# 手順②(ActiveHashのモデル作成)
1. `app/models`配下に、ActiveHashのモデルを手動作成する
    app/models/[ActiveHashのモデル名].rb
1. 作成したActiveHashのモデルに`ActiveHash::Base`を継承する
    ```[ActiveHashのモデル名].rb
    class モデル名 < ActiveHash::Base
    end
    ```
1. データは、配列にハッシュ形式で格納する
    ```app/models/genre.rb
    class Genre < ActiveHash::Base
     self.data = [
       { id: 1, name: '経済' },
       { id: 2, name: '政治' },
       { id: 3, name: '地域' },
       { id: 4, name: '国際' },
       { id: 5, name: 'IT' },
       { id: 6, name: 'エンタメ' },
       { id: 7, name: 'スポーツ' },
       { id: 8, name: 'グルメ' },
       { id: 9, name: 'その他' }
     ]
    end
    ```

# 手順③(アソシエーションを設定)
1. ActiveHashを利用するモデルに、アソシエーションを設定する
    1. `extend ActiveHash::Associations::ActiveRecordExtensions`と記述して、moduleを取り込む
    1. `belongs_to`を設定する
    ```app/models/article.rb
    class Article < ApplicationRecord
      extend ActiveHash::Associations::ActiveRecordExtensions
      belongs_to :genre
    end
    ```
1. ActiveHashのモデルに、アソシエーションを設定する
    - 保存データを使用(ビューなど)しない場合は、アソシエーションの定義は不要
    - 保存データを使用(ビューなど)する場合は、必ずアソシエーションを定義
        1. `include ActiveHash::Associations`と記述して、moduleを取り込む
        1. `has_many`を設定する
        ```app/models/genre.rb
        class Genre < ActiveHash::Base
         self.data = [
           { id: 1, name: '経済' },
           { id: 2, name: '政治' },
           { id: 3, name: '地域' },
           { id: 4, name: '国際' },
           { id: 5, name: 'IT' },
           { id: 6, name: 'エンタメ' },
           { id: 7, name: 'スポーツ' },
           { id: 8, name: 'グルメ' },
           { id: 9, name: 'その他' }
         ]
        
          include ActiveHash::Associations
          has_many :articles
         end
        ```

# 手順④(バリデーションを設定)
ActiveHashを利用するモデルに対して、バリデーションを設定する

1. 全項目NULLで保存できないように、最低1項目はNULL制約をつける
    ```app/models/article.rb
    class Article < ApplicationRecord
      extend ActiveHash::Associations::ActiveRecordExtensions
      belongs_to :genre
    
      #空の投稿を保存できないようにする
      validates :title, presence: true
    end
    ```
1. ActiveHashを紐づけている項目は、数値の場合のみデータを保存する
    ```app/models/article.rb
    class Article < ApplicationRecord
      extend ActiveHash::Associations::ActiveRecordExtensions
      belongs_to :genre
    
      #空の投稿を保存できないようにする
      validates :title, presence: true
    
      #数値以外を保存できないようにする
      validates :genre_id, numericality: true
    end
    ```

# 手順⑤(ビューでの表示)
1. データを表示する
    アソシエーションが定義されている場合、`単一レコード情報.ActiveHashを用いたモデル名.カラム名`で情報を取得できる
    ```erb
    <!-- コントローラーで、「@articles = Article.all」を定義 -->
    
    <% @articles.each do |article| %>
      <!-- ActiveHashで紐付けた情報を表示する -->
      <%= article.genre.name %>
    <% end %>
    ```
1. `collection_select`メソッドを使用して、form_withへ追加する
    ```erb
    <%= form_with model: @article, url:articles_path, local: true do |f| %>
      <%= f.text_field :title, class:"title", placeholder:"タイトル" %>
      <%= f.text_area :text, class:"text", placeholder:"テキスト" %>

      <!-- ActiveHashのモデルデータを表示 -->
      <%= f.collection_select(:genre_id, Genre.all, :id, :name, {}, {class:"genre-select"}) %>
      <%= f.submit "投稿する" ,class:"btn" %>
    <% end %>
    ```

# Ruby on Railsまとめ
https://qiita.com/likapantrip/items/46b43c9d1309b6633f0a