Railsのgem 'active_hash'で都道府県データを作成してみた
こんにちは!kossyです!
さて、今回はRailsでモデルに都道府県データを持たせずに、
active_hashで持たせる方法について、ブログに残してみたいと思います。
環境
Rails 5.2.3
Ruby 2.6.3
MacOS Mojave
active_hash 2.2.0
事前準備
例によってプロジェクトを新規作成して試してみます。
$ rails new active_hash_test $ cd active_hash_test
次にactive_hashを導入します。
./Gemfile gem 'active_hash'
で、bundle install。
$ bundle install
次にモデルを作成します。
$ 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:migrateします。
$ rails db:create $ rails db:migrate
次はモデル周りを記述します。
Addressモデルの編集とPrefectureモデルの作成
まず、Prefectureモデルを作成してみます。
モデルの作成、と言うと、rails g modelしたくなりますが、
今回はActiveHash::Baseを継承したPrefectureモデルを自作します。
ActiveHash::Baseを継承したモデルを作成すると、ActiveRecordのメソッド(allとか)が使えるようになります。
他にどんなメソッドが使えるようになるか気になる人は、下の手順でPrefectureモデルを定義して、コンソールで、
$ Prefecture.methods
と入力してみてください。
以下実装です。
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 app/models/address.rb class Address < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to_active_hash :prefecture end
belongs_to_active_hashメソッドでアソシエーションも組めるってわけです。
extend ActiveHash::Associations::ActiveRecordExtensionsしないとprefectureモデルを使えません。
詳しく知りたい方はGemの中を覗いてみてください。
参考: active_hash/associations.rb at master · zilkey/active_hash · GitHub
これで準備完了です。
では、コンソールで試してみます。
$ rails c # 以下はログです [1] pry(main)> @address_1 = Address.create(prefecture_id: 1, city: '函館市') (0.2ms) SAVEPOINT active_record_1 Address Create (41.0ms) INSERT INTO `addresses` (`prefecture_id`, `city`, `created_at`, `updated_at`) VALUES (1, '函館市', '2019-01-08 11:41:41', '2019-01-08 11:41:41') (0.3ms) RELEASE SAVEPOINT active_record_1 => #<Address:0x00007fc9f8cbf420 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: '新宿区新宿') (0.3ms) SAVEPOINT active_record_1 Address Create (0.3ms) INSERT INTO `addresses` (`prefecture_id`, `city`, `created_at`, `updated_at`) VALUES (13, '新宿区新宿', '2019-01-08 11:42:05', '2019-01-08 11:42:05') (0.2ms) RELEASE SAVEPOINT active_record_1 => #<Address:0x00007fc9f8a7cb40 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 でハッシュを取ってこれます。
都道府県を選択するセレクトボックスを生成したい時は、
# hamlで書いてます = f.collection_select :prefecture_id, Prefecture.all, :id, :name
って感じで、
こんな感じで設定できます。
検索機能も、詳細はこちらの記事に譲るとして、
Rails初心者が「form_with」を使って検索機能を実装してみた。 - Qiita
form_with でシンプルなサーチフォームを作成する | deadwood
こんな感じのチェックボックス式の検索フォームがあったとして、
view <%= f.collection_check_boxes :prefecture_id, Prefecture.all, :id, :name %> controller @results = Address.where('prefecture_id IN(?)', params[:prefecture_id])
IN検索機能を使って、受け取ったprefecture_idを持つAddressテーブルのレコードを取得しています。
蛇足ですが、delegateを使えば@address.nameでも県名が取れたりしちゃいます。
Active Support コア拡張機能 - Railsガイド
app/models/address.rb class Address < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to_active_hash :prefecture delegate :name, to: :prefecture end
ログ
@address = Address.create(prefecture_id: 1, city: '猿払村') @address.name => "北海道"
あとは、app/models/address.rbに、
def full_address "#{name}#{city}" #delegateしているのでnameだけで都道府県名が取れる end
メソッドを定義すると、
@address.full_addressで、
都道府県名と市町村を連名で表示するような実装もできます。
active_hashさん、Prefectureモデルに静的データを持たせるよりも楽でいいですね。
ちなみに、active_hashで静的データを持つことの是非についてはこちらが詳しかったです。
blog.sesere.net
参考にさせていただいたサイト
https://blog.sesere.net/entry/2017/07/23/180000_1
GitHub - zilkey/active_hash: A readonly ActiveRecord-esque base class that lets you use a hash, a Yaml file or a custom file as the datasource
https://blog.otsukasatoshi.com/entry/2017/04/20/003756
Active Support コア拡張機能 - Railsガイド