きっかけ
簡単なフリマアプリ作成中にactive_hashを使うタイミングがあり、
教材やネットで探して思ったのが、active_hashの作り方が何パターンかあるけど、
結局どれが一番いいんだって長いこと迷ったので、
自分的に一番簡単な方法をまとめてみようと思った🏄♂️
active_hashとは?
簡単に言うと、データベースに保存するまでもなく変更もしない情報を、モデル(モデルの類似、厳密にはモデルではない)に格納して繰り返し使うことができる機能。
王道の使い道は、よく見るこう言うやつで、出身地やなんかのカテゴリーをクライアントに選択させたいときなどに使う。(セレクトボックス型)
前提
※前提として、アクティブハッシュを使うときは、
カラム名に「_id」をつけなければいけないと言うルールがある。
例えば、userテーブル作成時に、アクティブハッシュを使ってprefectureカラム(userの出身地)のデータを保存したいと思ったら、この段階でカラムを「prefecture_id」で作らなければいけない。
そのため、最初のDB設計のときに使うときめて、予め「_id」をつけた状態でテーブルを作るか、途中で大元のテーブルを修正するかのどっちかになる。
今回は前者の予めidをつけた状態でテーブルを作った場合を説明する。
ちな、こんな感じでinteger型でないといけない
t.integer :delivery_fee_id, null: false
t.integer :prefecture_id, null: false
t.integer :shipping_time_id, null:false
使い方フロー
- gemのインストール (今回は割愛)
- 手動でモデルファイルの作成
- 作成したモデルファイルに格納したいデータを記述
- アソシエーションを記述
- セレクトボックスの作成
- 保存を許可するためにコントローラーの調整
- 必要であればバリデーションで未選択のまま保存させないようにする
あとは用途によって使い方を変える!
今回はよく見るセレクトボックスを作ってクライアントが選択できるようにする。
手動でモデルファイルの作成
ポイントはコマンドではなく手動で作ると言うこと。
コマンドで作成してしまうと、余計な手間が増えるので手動で作成!
(コマンドで作成して一手間増えてる作り方もあるので調べてみてください)
今回はCategoryモデル、
作成したモデルファイルに格納したいデータを記述
こんな感じ
class Category < 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: 'その他' }
]
include ActiveHash::Associations
has_many :items
end
一番上で
{ id: 0, name: '--' },
空欄 = id:0のハッシュとして、あとでバリデーションをかけて、id:0(空欄)を保存させないようにするため
アソシエーションの記述
上に書いてある通り、アクティブハッシュのモデルの方にhas_manyを書く、
has_many :items
また大元のItemモデルには
class Item < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
# もともと書いてある記述は省略しています
belongs_to :category
end
**ポイントは2つあります。
- このときの2つのテーブルの関係性で、アイテムは1つのカテゴリーに属していて、カテゴリーはたくさんのアイテムを持っているので1対多の関係と考えること。
- それぞれのファイルで
include ActiveHash::Associations
extend ActiveHash::Associations::ActiveRecordExtensions
の記述を忘れない💃**
ちなみに参考にしたサイトでは、Itemモデルにbelongs_toだけ記述してくださいと言っていたが、投稿主はそれでエラーになったので、has_manyも付け足して成功しました。
セレクトボックスの作成
こんな感じで、collection_selectを使う
<%= form.collection_select(:category_id, Category.all, :id, :name, {}, {class:"select-box", id:"item-category"}) %>
書き方に関してはhttps://pikawaka.com/rails/form_with#form.collection_select
わかりやすかったです🏄♂️
データの保存を許可する
itemsコントローラーにてcategory_idに入るデータの保存の許可をしてあげる,
private
def item_params
params.require(:item).permit(:image, :name, :info, :category_id, :price).merge(user_id: current_user.id)
end
end
#未選択を防止するバリデーション
itemモデルで
validates :category_id, numericality: { other_than: 0, message: 'Select' }
この記述で空欄を意味する id:0 のハッシュの保存を防止している
numericaltyはcategory_idカラムがinteger型だから使っている。
message: “エラー文” で表示させたいエラー文の指定
以上
取り出し方
※ここで言う取り出すとは、クライアントが一度アクティブハッシュのデータを保存して、
そのクライアントの選んだハッシュを取り出すこと
例えば今回の例で使うと、itemの新規登録で、商品の種類(category)をアクティブハッシュを使って保存させて、
その情報をitemの詳細ページに反映させたいとき!
この記述の仕方がなかなかわからんくて困りました、、、
結論、こうやって記述する
<%= @item.category.name %>
@item
の中身はitemコントローラーのshowアクションでこのように定義する
@item = Item.find(params[:id])
←該当するitemを当てはめている
category.name
は上で定義したアクティブハッシュのnameの値と言う意味
簡単にすると
該当するitem.アクティブハッシュを格納しているファイル名(.rbはいらない).表示させたい値のキー
参考文献