active_hashについて

##active_hashとは
gemの一種でハッシュのデータを、ActiveRecordと同じように使えるようにしてくれる。
都道府県など基本的に変更されないデータはデータベースに保存する必要性がなく、ビューファイルにデータを直接書いてしまうと、可読性に欠けてしまう。このような場面でactive_hashを使う。

##目標
簡単なActiveHashを使用したスポーツ記事の投稿アプリの作成(今回CSSは割愛)

##ActiveHashを導入

```
gem 'active_hash'
```

##モデルを作成する
次にモデルを作成する。
今回モデルはsportsモデルとgenreモデルの2つ作成する。
まずはrails g modelでsportsモデルを作成。

```
rails g model sports
```
次にgenreモデルを作成します。

```
rails g model genre --skip-migration
```
今回の--skip-migrationとは、モデルファイルを作成するときに、マイグレーションファイルの生成を行わないためのオプションです。

次にgenre.rbを編集していきます。
この時にActiveHash::Baseクラスを継承するようにします。ActiveHash::Baseを継承することで、ActiveRecordと同じようなメソッドを使用できるようになります。結果以下のようなオブジェクトを記述したとします。

```
class Genre < 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: 'スポーツ' }
 ]
 end
```
ジャンルのデータは、配列にハッシュ形式で格納しています。


またsportsモデルのマイグレーションファイルにgenre_idというカラムを追加することによってsportsテーブルのなかでGenreモデル（ActiveHash）のidを外部キーとして管理することで、その記事に紐付いたジャンルの取得ができるようになります。

```
class CreateSports < ActiveRecord::Migration[6.0]
 def change
   create_table :sports do |t|
     t.string     :title        , null: false
     t.text       :text         , null: false
     t.integer    :genre_id     , null: false     t.timestamps
   end
 end
end
```

```
$ rails db:create
$ rails db:migrate
```

##アソシエーションの設定
active_hashにはbelongs_to_active_hashメソッドが用意されているので、
sports.rbに このメソッドを記述し、アソシエーションを定義する。

```
class Sports < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :genre
end
```

##バリデーションを設定
先ほどのsports.rbにバリデーションを追記する。

```
class Sports < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :genre

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

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


##ルーティングの設定

```
Rails.application.routes.draw do
  root to: 'sportses#index'
  resources :sportses
end
```

##コントローラーとビューを作成

```
rails g controller sportses index new
```

###コントローラーの編集

```articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @sportses = Sports
  end

  def new
  end

  def create
    @sports = Sports.new(sports_params)
    if @sports.save
      redirect_to root_path
    else
      render :new
    end
  end

  private

  def sports_params
    params.require(:sports).permit(:title,:text,:genre_id)
  end
end
```

###ビューの編集

```app/views/articles/index.html.erb
<h1>記事一覧</h1>
<%= link_to "投稿する", new_sports_path, class:"post" %>

<% @sportses.each do |sports| %>
  <div class="sports">
    <div class="sports-genre">
      <%= sports.genre.name %>
    </div>
    <div class="sports-title">
      <%= sports.title %>
    </div>
    <div class="sports-text">
      <%= sports.text %>
    </div>
  </div>
<% end %>

```

##プルダウンバーの実装
記事投稿画面の実装です。

```app/views/articles/new.html.erb
<%= form_with model: @sports, url:sportses_path, local: true do |f| %>
  <div class="sports-box">
    記事を投稿する
    <%= f.text_field :title, class:"title", placeholder:"タイトル" %>
    <%= f.text_area :text, class:"text", placeholder:"テキスト" %>
    <%= f.collection_select(:genre_id, Genre.all, :id, :name, {}, {class:"genre-select"}) %>
    <%= f.submit "投稿する" ,class:"btn" %>
  </div>
<% end %>
```

collection_selectを使うことで先ほどのアクティブハッシュをプルダウン形式で使用することができる。
collection_selectは第一引数から第五引数まで存在し以下の順に引数を入力していく。
Genre.allによってgenre.rbのデータ（配列）を指定している。ビューでユーザーが実際に選んだスポーツ名はgenre_idとしてsportsモデルに保存されるという流れになる。

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

<%= f.collection_select(:genre_id, Genre.all, :id, :name, {}, {class:"genre-select"}) %>
```

##終わりに
初めてここまで本格的なアウトプットをしたので至らない部分は多かったと思う。編集してわかりやすいようにしていくが今回この記事を書くことによってアクティブハッシュに関する理解が自分の中でグッと整理できた。