シリアル化された列を使用するモデルがあります。
class Form < ActiveRecord::Base
serialize :options, Hash
end
このシリアル化でYAMLの代わりにJSONを使用する方法はありますか?
シリアル化された列を使用するモデルがあります。
class Form < ActiveRecord::Base
serialize :options, Hash
end
このシリアル化でYAMLの代わりにJSONを使用する方法はありますか?
Rails 3.1では、次のことができます
class Form < ActiveRecord::Base
serialize :column, JSON
end
それが役立つことを願っています
Rails 3.1 では、カスタム コーダーを で使用できますserialize
。
class ColorCoder
# Called to deserialize data to ruby object.
def load(data)
end
# Called to convert from ruby object to serialized data.
def dump(obj)
end
end
class Fruits < ActiveRecord::Base
serialize :color, ColorCoder.new
end
お役に立てれば。
参考文献:
の定義serialize
:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L556
Rails に同梱されているデフォルトの YAML コーダー: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/coders/yaml_column.rb
そして、これが呼び出しが行われる場所load
です:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/read.rb#L132
アップデート
より適切な Rails >= 3.1 の回答については、以下の mid の高評価の回答を参照してください。これは、Rails < 3.1 に対する優れた回答です。
おそらくこれはあなたが探しているものです。
Form.find(:first).to_json
アップデート
1) 「json」gemをインストールします。
gem install json
2) JsonWrapper クラスを作成する
# lib/json_wrapper.rb
require 'json'
class JsonWrapper
def initialize(attribute)
@attribute = attribute.to_s
end
def before_save(record)
record.send("#{@attribute}=", JsonWrapper.encrypt(record.send("#{@attribute}")))
end
def after_save(record)
record.send("#{@attribute}=", JsonWrapper.decrypt(record.send("#{@attribute}")))
end
def self.encrypt(value)
value.to_json
end
def self.decrypt(value)
JSON.parse(value) rescue value
end
end
3) モデル コールバックを追加します。
#app/models/user.rb
class User < ActiveRecord::Base
before_save JsonWrapper.new( :name )
after_save JsonWrapper.new( :name )
def after_find
self.name = JsonWrapper.decrypt self.name
end
end
4) テストしてみよう!
User.create :name => {"a"=>"b", "c"=>["d", "e"]}
DRYとまではいきませんが、頑張りました。誰かがモデルを修正できればafter_find
、User
それは素晴らしいことです。
私の要件では、この段階で多くのコードを再利用する必要はありませんでした。そのため、私の抽出したコードは上記の回答のバリエーションです。
require "json/ext"
before_save :json_serialize
after_save :json_deserialize
def json_serialize
self.options = self.options.to_json
end
def json_deserialize
self.options = JSON.parse(options)
end
def after_find
json_deserialize
end
乾杯、最後はとても簡単です!
デフォルトを使用する独自のYAMLコーダーを作成しました。クラスは次のとおりです。
class JSONColumn
def initialize(default={})
@default = default
end
# this might be the database default and we should plan for empty strings or nils
def load(s)
s.present? ? JSON.load(s) : @default.clone
end
# this should only be nil or an object that serializes to JSON (like a hash or array)
def dump(o)
JSON.dump(o || @default)
end
end
load
およびはインスタンスメソッドであるため、モデル定義dump
の2番目の引数としてインスタンスを渡す必要があります。serialize
その例を次に示します。
class Person < ActiveRecord::Base
validate :name, :pets, :presence => true
serialize :pets, JSONColumn.new([])
end
新しいインスタンスを作成し、インスタンスをロードし、IRBにインスタンスをダンプしようとしましたが、すべて正常に機能しているように見えました。私もそれについてブログ記事を書きました。
serialize :attr, JSON
usingcomposed_of
メソッドは次のように機能します。
composed_of :auth,
:class_name => 'ActiveSupport::JSON',
:mapping => %w(url to_json),
:constructor => Proc.new { |url| ActiveSupport::JSON.decode(url) }
ここで、url は json を使用してシリアル化される属性であり、auth はモデルで使用できる新しいメソッドであり、その値を json 形式で url 属性に保存します。(まだ完全にはテストされていませんが、動作しているようです)
より簡単な解決策は、MichaelRykovによるこのブログ投稿composed_of
で説明されているように使用することです。使用するコールバックが少ないため、このソリューションが気に入っています。
その要点は次のとおりです。
composed_of :settings, :class_name => 'Settings', :mapping => %w(settings to_json),
:constructor => Settings.method(:from_json),
:converter => Settings.method(:from_json)
after_validation do |u|
u.settings = u.settings if u.settings.dirty? # Force to serialize
end
アレラン、Rails 3 でこの方法を使ったことはありますか? 私はいくぶん同じ問題を抱えており、Michael Rykov によるこの投稿に出くわしたときに連載に向かっていましたが、彼のブログ、または少なくともその投稿にコメントすることはできません。私の理解では、彼は設定クラスを定義する必要はないと言っていますが、これを試してみると、設定が定義されていないことがわかります。それで、あなたがそれを使用したかどうか、さらに何を説明すべきか疑問に思っていましたか? ありがとう。