Issue with PaperTrail gem and yaml conversion of bitmask_attributes
PaperTrail is a handy gem that lets you track old versions of models. It tracks by doing:
string = model.changes.to_yaml
Then later parsing them back with
YAML::load(string)
Unfortunately this fails when you've changed something with Bitmask Attributes. In my model I have:
bitmask :days_of_week, :as => [:sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday]
If I set it to [:saturday], then reload, I see the value of days_of_week is 64. If I set it to [:monday, :tuesday] and call b.changes, I see:
1.9.2p318 > b.changes
=> {"days_of_week"=>[64, [:monday, :tuesday]]}
If I convert to yaml and back I get:
1.9.2p318 > b.changes.to_yaml
=> "--- !map:ActiveSupport::HashWithIndifferentAccess \ndays_of_week: \n- 64\n- !seq:BitmaskAttributes::ValueProxy \n - :monday\n - :tuesday\n"
1.9.2p318 > YAML.load(b.changes.to_yaml)
NoMethodError: undefined method `key?' for nil:NilClass
from /Users/glenn/.rvm/gems/ruby-1.9.2-p318/gems/bitmask_attributes-0.3.0/lib/bitmask_attributes/value_proxy.rb:35:in `block in validate!'
from /Users/glenn/.rvm/gems/ruby-1.9.2-p318/gems/bitmask_attributes-0.3.0/lib/bitmask_attributes/value_proxy.rb:34:in `each'
from /Users/glenn/.rvm/gems/ruby-1.9.2-p318/gems/bitmask_attributes-0.3.0/lib/bitmask_attributes/value_proxy.rb:34:in `validate!'
from /Users/glenn/.rvm/gems/ruby-1.9.2-p318/gems/bitmask_attributes-0.3.0/lib/bitmask_attributes/value_proxy.rb:48:in `updated!'
Do you have any suggestions for what I can do about this? I'm not sure if the problem should be solved so that .changes returns something different, or if it's a yaml conversion thing that needs to be addressed. Either way I'd really appreciate your help. Thanks!
I'm not sure if this is the best solution, but this has helped me:
module BitmaskAttributes
class ValueProxy
def to_yaml(options={})
self.to_i.to_yaml(options)
end
end
end
I'm struggling with the same issue even if I'm not using Papertrail. In one of my projects I need to extract the difference resulting from foo.changes when I change the bitmask attributes.
I'm not fond of overriding methods of ActiveModel::Dirty. One of the possible solutions could be to write a method to return the difference in one of these two ways:
{"days_of_week"=>[[:saturday], [:monday, :tuesday]]}
#or
{"days_of_week"=>[64, 19]} #substitute 19 with the new bitmask integer value
< goes to dig the source to find how the reverse bitmask method in the gem is called >