kobasaです(´ω`*)商品出品機能で盛大に詰まってましたw
夕方までにレビュー依頼出すつもりだったんだけどなぁ。ActiveHashにやられました。
ActiveHash
ActiveHashとは
カテゴリーや都道府県など、「基本的に変更されないデータ」はデータベースに保存する必要がない。
ActiveHashを使用すると変更されないデータをモデルファイル内に直接記述することで、データベースに保存せずにデータを取り扱うことができる。
また、モデルに記述したデータに対してActiveRecordのようなメソッドを用いることができる。
Gemの導入とマイグレーションファイルの記述
ActiveHashはGemなのでまずはGemファイルに記述してbundle install
gem 'active_hash'
次にマイグレーションファイルの記述。
class CreateItems < ActiveRecord::Migration[6.0]
def change
create_table :items do |t|
t.string :name, null: false
t.text :description, null: false
t.integer :category_id, null: false
t.integer :item_status_id, null: false
t.integer :price, null: false
t.references :user, foreign_key: true
t.timestamps
end
end
end
商品(item)を表示するときに「変更されないデータ(categoryやitem_status)」を紐付けて取得するため、末尾に「_id」をつけたカラム名で保存する。
データの項目名をidで管理する。idは数値になるのでinteger型を指定。
モデルファイルの記述
変更されないデータのモデルファイルの記述
次に「変更されないデータ名」でモデルファイルを作成する。
「item_status.rb」など(末尾に_idは不要)。
class ItemStatus < ActiveHash::Base
self.data = [
{ id: 1, item_status: '---' },
{ id: 2, item_status: '未使用に近い' },
{ id: 3, item_status: 'やや傷や汚れあり' },
{ id: 4, item_status: '全体的に状態が悪い' }
]
include ActiveHash::Associations
has_many :items
end
①1行目でクラスを定義し、ActiveHash::Baseクラスを継承する。
※ファイル名で単語の区切りに_を使用してもクラス名では大文字で単語を区切ること!
②2〜7行目でデータを配列にハッシュ形式で格納する。
idと項目名(item_statusの部分。任意の名前)でデータを記述していく。
データベースにはidの値、integer型で保存する。
※integer型は0から始まる値は識別できない?ため、未選択を表す ‘—‘のidは1にしておく。
③9〜10行目ではアソシエーションの記述をしている。
ActiveHashを使用する場合は9行目の記述をし、10行目でデータを保存するテーブルとの関係を記述している。
変更されないデータ名は複数の出品(item)に選択されるのでhas_many。
出品側のモデルファイルの記述
class Item < ApplicationRecord
# バリデーションの設定
with_options numericality: { other_than: 1, message: "can't be blank" } do
validates :category_id
validates :item_status_id
end
# アソシエーションの設定
has_one_attached :image
belongs_to :user
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :category
belongs_to :item_status
end
④numericalityは数値かどうかを検証するバリデーション。数値以外は保存しない。
項目名はidの値で保存されるためnumericalityを使用する。
またid:1は未選択’–‘とみなし、保存したくないのでother_than: 1と記述する。
これでid:1以外なら保存できる。
そのままだとエラーメッセージが伝わりづらいものになるため、
messageオプションで “can’t be blank”を指定している。
データベースのカラム名にバリデーションをかけるため_idが必要
⑤ActiveHashを使用したアソシエーションの記述。
選択項目との関係はbelongs_to。モデルとの関係性のため_idは不要
プルダウンでデータを表示させる
<%= form_with model: @item, url: items_path, local: true do |f| %>
<%= f.collection_select(:item_status_id, ItemStatus.all, :id, :item_status, {}, {class:"select-box", id:"item-sales-status"}) %>
<% end %>
collection_selectメソッドを使用することで、データをプルダウン形式で表示することができる。
- 第一引数:DB保存先のカラム名。
- 第二引数:配列データの指定。メソッドで範囲指定も可。
- 第三引数:カラムに保存される項目。
- 第四引数:プルダウンに表示される項目名。
- 第五引数:オプション。ない場合は{}。
- htmlオプション:クラス名など。
①DBに保存するカラム名なので_idが必要。
②配列は変更されないデータのモデルファイル内にあるためクラス名を記述。
全てのデータを取得するのでallメソッドを使用。
③DBに保存される値の項目名(id:)
④プルダウンに表示される値の項目名(:item_status)。ハッシュ内で任意で指定したやつ。
まとめ
_idの有無や、カラム名に_を使用した場合はクラス名の記述に注意!
コメント
アソシエーションのときの記述ほんとぐっちゃぐちゃなりますね
このときはこう!みたいな表(チートシート)作ったほうがええんかな……
チートシートあると便利そうですね(´ω`*)
ActiveHash自体は便利なんですけど記述がややこしい。
コピペでいけるところはコピペしたいです。