##active_hashってなに?
gemの一種。
ハッシュのデータを、ActiveRecordと同じ感覚で使えるようにしてくれる。
##どういうときにつかうの?
以下の条件2つにあてはまるとき。
◆これから扱うデータがDBにデータとして保存しておくほど重要ではない、かつ、基本的に変更されない。
◆ActiveRecordと同じ感覚でデータを操作したい。
##具体的に言うと?
例えば都道府県名一覧やカテゴリなど「基本的に変更されないデータ」があったとする。
そういったデータをDBに保存しておけば取り扱いは楽だけど、データの価値としてはDBに保持しておくほど重要ではない。
じゃあ ↓ の例のように定数でやるか?というとそれも微妙。
コード全体の見通しが悪くなるし、Activerecordを通して使えないので扱いづらくなってしまう。
TODOHUKEN = [
1: {name: :北海道, location: [12.323245, 102.3231231]},
.
.
.
]
そういう悩みを解決するのに便利なのがactive_hash。
ハッシュデータをモデルとして定義することで、
ハッシュをDBから引っ張ってきたデータと同じように扱うことができるようになる。
概要はここまで。次は実際の使い方を紹介。
##導入方法
Gemfileにactive_hashを記載して、bundle install
導入はこれでおしまい。カンタン。
gem 'active_hash'
##モデル作成
次にモデルを作成する。
今回作成するモデルは2つ、AddressモデルとPrefectureモデル。
まずはrails g model
でAddressモデルを作成。
続けてdb:create
とdb:migrate
を実行。
$ rails g model Address prefecture_id:integer city:string
Running via Spring preloader in process 21996
invoke active_record
create db/migrate/20190108110055_create_addresses.rb
create app/models/address.rb
invoke test_unit
create test/models/address_test.rb
create test/fixtures/addresses.yml
$ rails db:create
$ rails db:migrate
次にPrefectureモデルを作成。
こちらはrails g model
での作成ではなく
ActiveHash::Baseを継承したPrefectureモデルを 自作 する。
※ActiveHash::Baseを継承することで初めて、ActiveRecordのメソッド(allなど)が使えるようになる。
都道府県のデータはハッシュで配列に格納する。
class Prefecture < 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: '茨城県'}, {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: '沖縄県'}
]
end
active_hashにはbelongs_to_active_hashメソッドが用意されているので、
address.rbに このメソッドを記述し、アソシエーションを定義する。
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to_active_hash :prefecture
この2行を追加。
なお、Prefectureモデルのファイルには、アソシエーションを明示する必要はない。
これで準備は完了。
class Address < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to_active_hash :prefecture
end
##コンソールで試してみる
$ rails c
[1] pry(main)> @address_1 = Address.create(prefecture_id: 1, city: '函館市')
id: 1,
prefecture_id: 1,
city: "函館市",
created_at: Tue, 08 Jan 2019 11:41:41 UTC +00:00,
updated_at: Tue, 08 Jan 2019 11:41:41 UTC +00:00>
[2] pry(main)> @address_2 = Address.create(prefecture_id: 13, city: '新宿区新宿')
id: 2,
prefecture_id: 13,
city: "新宿区新宿",
created_at: Tue, 08 Jan 2019 11:42:05 UTC +00:00,
updated_at: Tue, 08 Jan 2019 11:42:05 UTC +00:00>
##############################
[3] pry(main)> @address_1.prefecture.name
=> "北海道"
[4] pry(main)> @address_2.prefecture.name
=> "東京都"
って感じで、prefecuture_idにPrefectureモデルに定義したハッシュのidを渡して、
@address.prefecture.nameで名前を取れる。
もちろんPrefecture.find でハッシュを取ることも可能。
##まとめ
テーブルの数を無駄に増やさないためにも、
扱うデータが最初の2つの条件にあてはまる場合はactive_hash
を活用していきましょう。
#※以下は補足情報
##使えるクラスメソッド
Country.all # => returns all Country objects
Country.count # => returns the length of the .data array
Country.first # => returns the first country object
Country.last # => returns the last country object
Country.find 1 # => returns the first country object with that id
Country.find [1,2] # => returns all Country objects with ids in the array
Country.find :all # => same as .all
Country.find :all, args # => the second argument is totally ignored, but allows it to play nicely with AR
Country.find_by_id 1 # => find the first object that matches the id
Country.find_by_name "foo" # => returns the first object matching that name
Country.find_all_by_name "foo" # => returns an array of the objects with matching names
Country.find_by_id_and_name 1, "Germany" # => returns the first object matching that id and name
Country.find_all_by_id_and_name 1, "Germany" # => returns an array of objects matching that name and id
##使えるインスタンスメソッド
Country#id # => returns the id or nil
Country#id= # => sets the id attribute
Country#quoted_id # => returns the numeric id
Country#to_param # => returns the id as a string
Country#new_record? # => returns true if is not part of Country.all, false otherwise
Country#readonly? # => true
Country#hash # => the hash of the id (or the hash of nil)
Country#eql? # => compares type and id, returns false if id is nil
##注意点
検索
ActiveRecordのincludesやjoinsを使ってテーブル間の検索をするのは(たぶん)無理なので、
おとなしくmigrationファイルでActiveRecordを使用したほうが良さそう。