Posted in
ruby,
ruby on rails at 8月 16th, 2010.
No Comments.
DBに配列やハッシュのデータを保存したいなと思って調べました。
ActiveRecord.serializeで実に簡単に実現できるんですね。
http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M002229
If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, then specify the name of that attribute using this method and it will be handled automatically.
The serialization is done through YAML. If class_name is specified, the serialized object must be of that class on retrieval or SerializationTypeMismatch will be raised.
このメソッドでオブジェクトとして保存・取得したい属性の名前を指定すると、自動的に処理されるようになる。
YAMLでシリアライズされ、class_nameオプションが指定されると格納できるオブジェクトのクラスを制限できる。あるいはSerializationTypeMismatchの例外となる。
ポイント
- シリアライズしたいカラムの型をtextにする
- serializeメソッドでカラムを指定する
- 格納できるクラスを指定可能
- 内部的にはYAML
実例
さて、やってみます
まずマイグレーション内で、text型のdataというフィールドを用意する。
ここにシリアライズしたデータが格納されます。
class CreateItems <ActiveRecord::Migration
def self.up
create_table :items do |t|
t.text :data
end
end
def self.down
drop_table :items
end
end
そしてモデル内でシリアライズするフィールドを指定。
class Item <ActiveRecord::Base
# シリアライズされたデータとして扱いたいフィールドを指定する
serialize :data
end
script/consoleなどをおもむろに起動し、本当にオブジェクトが保存できるのか確認します。
# 配列を代入する
Item.create :data => [1,2,3]
item = Item.find(:all).last
p item.data #=>[1,2]
p item.data.class #=>Array
ちゃんと配列として取得できました。めでたしめでたし。
どうなってるの?
DBに格納する際にオブジェクトをYAML化しているようです。
検索したい場合
findしたい場合は、オブジェクトではなく文字列として評価されてしまうので
Object#to_yamlを使うことになります。
Item.find_by_params([1,2,3]) # => これではレコードが見つからない
Item.find_by_params([1,2,3].to_yaml) # => 見つかる
使い勝手が悪い。。
格納する型を限定する
このままだとオブジェクトならなんでも格納できてしまいます。
そこで格納するクラスを指定してやります。
class Item <ActiveRecord::Base
# 配列以外のクラスは格納しない
serialize :data, Array
end
script/consoleで試してみます
# 配列の格納は成功
>> Item.create :data => ['bob','alice']
=> #<item id: 1, data: ["bob", "alice"]>
# ハッシュの格納は例外が発生する
>> Item.create :data => {:name => 'bob'}
ActiveRecord::SerializationTypeMismatch: data was supposed to be a Array, but was a Hash
これでかなり使い勝手が良くなりましたけど、配列の中身までは保証できないので、精神的安定のために使う程度でしょうか?
最後に
DBにシリアライズしたデータを保存しなければならない状況は無いにこした事は無いと思いますので
設計レベルで回避できる場合はそちらをおすすめします。
Posted in
ruby on rails,
日記 at 5月 21st, 2009.
No Comments.