Help us understand the problem. What is going on with this article?

active_hashまとめ

More than 1 year has passed since last update.

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
導入はこれでおしまい。カンタン。

Gemfile
gem 'active_hash'

モデル作成

次にモデルを作成する。
今回作成するモデルは2つ、AddressモデルとPrefectureモデル。
まずはrails g modelでAddressモデルを作成。
続けてdb:createdb: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など)が使えるようになる。

都道府県のデータはハッシュで配列に格納する。

app/models/prefecture.rb
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モデルのファイルには、アソシエーションを明示する必要はない。

これで準備は完了。

app/models/address.rb
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を使用したほうが良さそう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away