1. 背景
タイトルの通り都道府県をプルダウンで選択できるようにする方法をまとめました。
始めは、htmlをべたっと書いていたのですが、Active_Hashと言うものの存在を知り、そちらに移行しようとしました。
2. Active_Hashとは
初心者には以下の説明がわかりやすかったので引用。
Active_Hashとは、都道府県名やカテゴリー選択などの変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるgemです。
Active_Hashを用いることで、モデルファイルに直接記述した変更されないデータに対して、ActiveRecordのメソッドを用いることができます。
3. gem の追加
Gemfileに追記したのち、bundle install
する。
gem "active_hash"
4. modelの追加
私は手動で、modelsフォルダ直下にprefecture.rbを作成しました。
ActiveHash::Baseを継承したPrefectureクラスを作成します。
id:1がコメントアウトしてあるのは、作成したけれど不要になったからです。
class Prefecture < ActiveHash::Base
self.data = [
# {id:1, name:'選択してください'},
{id:2, name:'オンラインショップのみ'},
{id:3, name:'北海道'},
{id:4, name:'青森県'},
(略)
]
include ActiveHash::Associations
has_many :shops
end
associationsについては、正直まだ完全に理解していないのですが、モデル同士の関連付けを行うものだそうです(詳しくは、Railsガイドへ)。これによりモデルの操作を一貫させることができるらしい。
私が作成しているアプリケーションは、お店の情報を記録するデータベース(shopモデル)を持っているので、has_many :shops
となっています。has_many
は、1対多のつながりを表しています。
4. 既存のmodelにassociationsを追加
has_many
に対して、belongs_to
関連付けを行います。今回の場合、1つのお店に対して、1つの都道府県を割り当てたいという形です。
class Shop < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :prefecture
end
5. 入力欄の作成
入力欄にプルダウンを追加します。モデルの情報をもとにプルダウンを作成するf.collection_select
メソッドを使用しました。
f.collection_select(カラム名, プルダウンの表示に使うデータの配列, {オプション}, {HTMLオプション}
カラム名 | コントローラで値を受け取る時の名前。params[:カラム名] |
プルダウンの表示に使うデータの配列 | モデルに設定した都道府県データ |
オプション | デフォルト値などを設定することができる。オプションを設定しない場合でも{}は、入力が必要 |
HTMLオプション | idやclassを設定したい場合に入力 |
今回は以下のような形で設定しました。
<%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {prompt: "選択してください"}, {class:"new-wrapper__main__input-select", id:"item-prefecture"}) %>
参考にしたページ
6. form_withヘルパーの追加
私はform_tagしか使ったことがない状況だったため、"f"が未定義というエラーに遭遇して、"f"とは?とさまよいました。以下のようなコードの"f"でした(初学者過ぎる)。
<%= form_with model: @user do |f| %>
<!--フォーム内容 -->
<% end %>
参考にしたページ
https://qiita.com/YokoYokoko/items/77d0043e12406c7cec9e
form_withヘルパーは、URL、スコープ、モデルなどからフォームタグを生成してくれます。
Rails ドキュメントを見てなんとなく意味が分かりました。
今後どうするかは別として、とりあえずform_tag的な使い方ができればよかったので、以下のようにしました。f.submit
を設定することで、<input type="submit"~>
のタグが生成され、ボタンを押すと設定したurlに遷移します。
<%= form_with url: {controller: 'shops', action: 'create'}, method: :post do |f| %>
<%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {prompt: "選択してください"}, {class:"new-wrapper__main__input-select", id:"item-prefecture"}) %>
<%= f.submit "作成" %>
<% end %>
参考にしたページ(既に1度参照していますが)
ここまでくればプルダウンは生成されたはずです。
2024/10/11 追記
とりあえずform_tag的な使い方をしましたが、validation
の設定をして発生したエラーを出力しようとした辺りでエラーが発生しました。
解決の糸口になったのは、以下の記事です。非同期通信をするAjaxという仕組みがform_with
では、自動的に設定される(?)ようです。
Ajaxの説明
私は、上記を参考に対応しても状況が変わらず、以下の記事に記載のとおりrenderに(status: :unprocessable_entity)
を追加することで解決しました。
if @shop.save
flash[:notice] = "お店を投稿しました"
redirect_to shops_path
else
flash.now[:notice] = "登録できませんでした"
render new_shop_path, status: :unprocessable_entity
end
7. 保存したデータから、都道府県を参照して出力する
他のモデルと同じようにfind_by
メソッドを使用して出力できます(それはそう)。
私はshopモデルのprefecture_idに、入力されたprefecture_idを保存しているので以下の形です。
prefecture = Prefecture.find_by(id: shop.prefecture_id)
prefecture.name
参考にしたページ
https://pikawaka.com/rails/active_hash
おわりに
自分があまりにも初学者過ぎて(ここには書いていない無関係なエラーにも悩まされ)愕然としておりますが、先人のお知恵をお借りして何とか実現できました。ありがとうございました。