rails4で正式にサポートされたPostgreSQLのデータ形式「hstore」を実際に扱ってみる。
基本的にここ(Using Hstore with Rails 4)を訳しただけな内容だけど、ちょっと補足もあります。
最初の準備
PostgreSQLのhstore extensionを有効にする。
class AddHstoreSupport < ActiveRecord::Migration
def up
execute 'CREATE EXTENSION hstore'
end
def down
execute 'DROP EXTENSION hstore'
end
end
hstoreのカラムを作る。
add_columnなりcreate_tableなりで自由にどうぞ
add_column :users, :settings, :hstore
create_table :users do |t|
t.string :email
......
t.hstore :settings
end
実際に使うために
modelでhstoreで扱うキーのaccessorを設定する。
ActiveRecord::Storeを使うんだけど、http://api.rubyonrails.org/classes/ActiveRecord/Store.html に書いてあるようにPostgreSQLのhstoreやjson型を使う場合にはserializationとかしなくてもstore_accessorを設定すればよしなにやってくれる。
NOTE - If you are using PostgreSQL specific columns like hstore or json there is no need for the serialization provided by store. Simply use store_accessor instead to generate the accessor methods. Be aware that these columns use a string keyed hash and do not allow access using a symbol.
validationも普通に使える。つまりhstore内のkey,valueをそれぞれ独立したカラムとして扱うことが可能になる。
class User < ActiveRecord::Base
# setup hstore
store_accessor :settings, :favorite_color, :time_zone
# can even run typical validations on hstore fields
validates :favorite_color,
inclusion: { in: %w{blue, gold, red} }
validates_inclusion_of :time_zone,
in: ActiveSupport::TimeZone.zones_map { |m| m.name },
message: "is not a valid Time Zone"
end
Active Admin
store_accessorできちんと設定しておけばちょっとの変更でActive Adminでもhstoreを扱うことができる。
app/admin/users.rb
ActiveAdmin.register User do
permit_params :email, ......., :favorite_color, :time_zone
form do |f|
f.inputs do
f.input :email
.........
f.input :favorite_color
f.input :time_zone
end
f.actions
end
checkboxとかを設定したい場合はFormtastic的に明示的に指定すればオッケー。
f.input :is_free, :as => :boolean
booleanはデータベースにはテキストとして保存される。
settings: {"is_free"=>"0"}
まとめ
PostgreSQL依存のデータ型なので使うのためらう感じもするけど、別にデータベース変える予定ないしという場合なら積極的に使っていくと便利な機能ではないかと。ER図みてもデータベース全体が見通せなくはなるけれど、Modelだけの修正で扱うデータが自由に変更出来るメリットは大きいと思います。
あと、store_accessorに気付くまではactive adminで「hstoreなんかしらねーよ」といわれて挫けそうでした。このへんみると同じように泣いてる人が。store_accessor大事!