※2022年から技術系の記事は個人ブログに投稿しております。ぜひこちらもご覧ください→yamaday0u Blog
ActiveHashとは
都道府県名などの変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるgemです。
ActiveHashを導入すれば、以下のようなプルダウンメニューを作成するときに大いに役立ちます。
ActiveHashを導入する目的
ユーザー情報のような編集されることがあるデータと違って、都道府県名などは変更されないデータなので、データベースにわざわざ保存する必要がありません。
かといってビューファイルに直接都道府県名のプルダウンメニューを作ってしまうとコードが肥大化して可読性が下がってしまいます。
そこでActiveHashを使ってモデルからデータを呼び出すという方法を採ることでコードの管理がしやすくなります。
プルダウンメニューの実装
住んでいる都道府県を投稿するアプリを使って説明します。
以下のコマンドを入力してRailsアプリを作成します。
rails _6.0.0_ new activehash_app -d mysql
rails db:create
続いて、モデル、コントローラー、ビューを用意します。
モデルを作成
rails g model address
上記コマンドで生成されたマイグレーションファイルにname
カラムとprefecture_id
カラムを以下のとおり記述してマイグレートします。
prefecture_id
カラムには、後でActiveHash gemで導入するプルダウンメニューの情報が入ります。
データ型がinteger型なのは、のちに作成するprefectureのデータをアソシエーションのようにidから引用するためです。
class CreateAddresses < ActiveRecord::Migration[6.0]
def change
create_table :addresses do |t|
t.string :name, null: false
t.integer :prefecture_id, null: false
t.timestamps
end
end
end
rails db:migrate
コントローラーとビューを作成
下記のコマンドでコントローラーに加えて、一覧表示と新規投稿のビューをまとめて作成します。
rails g controller addresses index new
コントローラーとビュー(index
とnew
)を以下のように記述します。
class AddressesController < ApplicationController
def index
@addresses = Address.order("created_at DESC")
end
def new
@address = Address.new
end
def create
@address = Address.new(address_params)
if @address.valid?
@address.save
return redirect_to root_path
else
render "new"
end
end
private
def address_params
params.require(:address).permit(:name, :prefecture_id)
end
end
<h1>あなたの住んでいる都道府県は?</h1>
<%= link_to "投稿する", new_address_path %>
<div>
<ul>
<% if @addresses %>
<% @addresses.each do |address| %>
<li>
<%= address.name %>
<%= address.prefecture.name %>
</li>
<% end %>
<% end %>
</ul>
</div>
<%= form_with model: @address, url:addresses_path, local: true do |f| %>
<div class="article-box">
あなたの名前と住んでいる都道府県を投稿する
<div>
<p><%= f.text_area :name, placeholder:"あなたの名前" %></p>
<p><%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"genre-select"}) %></p>
<%= f.submit "投稿する" ,class:"btn" %>
</div>
</div>
<%= link_to "戻る", root_path %>
<% end %>
ActiveHashの導入
いよいよActiveHashを導入します。
Gemfile
の一番下に下記の記述をして、ターミナルでbundle install
します。
gem 'active_hash'
bundle install
都道府県のリストを用意するため、prefectureモデルを作成します。
ここで、いつものrails g model :モデル名
コマンドに--skip-migration
というオプションを付けます。
--skip-migration
はマイグレーションファイルの作成をスキップしてくれるオプションです。都道府県に関する情報はデータベースに保存しないためです。
rails g model prefecture --skip-migration
作成したprefecture.rb
に、以下のように記述します。
class Prefecture < ActiveHash::Base
self.data = [
{id: 0, name: '--'}, {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 #ActiveHashに定義されているモジュールを読み込み
has_many :address #addressモデルとのアソシエーションを定義
end
都道府県のデータを配列にハッシュ形式で入れます。
また、include ActiveHash::Associations
でActiveHashに定義されているモジュールを読み込み、has_many
を記述してAddressモデルとのアソシエーションを定義しています。
ActiveHashのモジュールについては公式GitHubのREADMEとライブラリを参照してください。
address.rb
にも同様に、モジュールを読み込み、belongs_to
でPrefectureモデルとのアソシエーションを定義します。
class Address < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions #Activehashに定義されているモジュールを読み込み
belongs_to :prefecture #prefectureモデルとのアソシエーションを定義
end
上記のアソシエーションを定義することで、先ほど作成したindex.html.erb
でPrefectureモデルに格納した都道府県名にアクセスできるようになりました。
<h1>あなたの住んでいる都道府県は?</h1>
<%= link_to "投稿する", new_address_path %>
<div>
<ul>
<% if @addresses %>
<% @addresses.each do |address| %>
<li>
<%= address.name %>
<%= address.prefecture.name %><%# アソシエーション定義によってprefecure.rbに格納している都道府県名にアクセスできる %>
</li>
<% end %>
<% end %>
</ul>
</div>