-
-
Save fgrehm/1917450 to your computer and use it in GitHub Desktop.
require 'json' | |
Virtus::Coercion::String.class_eval do | |
def self.to_hash(value) | |
JSON.parse(value) | |
end | |
end | |
module MyApp | |
module Attributes | |
class JSON < Virtus::Attribute::Object | |
primitive ::Hash | |
coercion_method :to_hash | |
end | |
end | |
class User | |
include Virtus | |
attribute :info, Attributes::JSON | |
end | |
end | |
@user = MyApp::User.new(:info => '{"email":"john@domain.com"}') | |
@user.info.class # => Hash | |
@user.info = {'new' => 'info'} # => Doesn't throw an exception :) |
How about something like this:
def Virtus::Coercion::String.to_json(value)
JSON.parse(value)
end
def Virtus::Coercion::Object.to_json(value)
json = coerce_with_method(value, :to_json)
json.equal?(value) ? value : String.to_json(json)
end
The implementation of this might work, but I'm having trouble with the proposed name of your Attribute class. I mean, if it really was a JSON field, then I would assume it was a JSON string, not an arbitrary ruby Object (or a Hash if you decide to restrict it that way). The naming is what threw me off above, and it still sticks out as something I might consider changing if I were modelling this.
With Virtus you're more focused around what the type of the attribute in the instance should be, not necessarily the serialization method used for the input. Sure, there are common coercions where it's unambiguous, like coercing "1"
into 1
for an Integer attribute, but there's no way to say "this is a Hash, but it could come in as a Hash or as a String in JSON encoding".
I'm almost wondering if this is the kind of thing a form plugin would handle, like @emmanuel's conformitas. If I was writing a pure ruby object without Virtus or another framework I would almost certainly not handle deserialization inside the object, but I would have something that knows how to take the input and then create the object from it. It's often in bloated frameworks where the model handles this (and usually dozens of other responsibilities), but I'm not sure the core objects should know about that kind of thing.
oh, woops. I realize I might be confusing
#to_json
with the fact that it's really being converted from json. sorry about that. lemme think about a more clear way to handle that.