serializing an IceCube object for Mongoid
-
06-07-2021 - |
题
I found this article: Override a Mongoid model's setters and getters to help me, but behavior's still not what I am looking for.
My model is like so:
class Event
include Mongoid::Document
include IceCube
validates_presence_of :title
field :title, type: String
field :description, type: String
field :schedule, type: Hash
attr_protected :schedule_hash
def schedule=(new_schedule)
super(new_schedule.to_hash)
end
def schedule
Schedule.from_hash(super())
end
end
This works more or less as I'd expect, in that it serializes and deserializes the IceCube object, but what I noticed is that while I can do this:
s = Schedule.new(Time.now)
s.add_recurrence_rule Rule.daily
e = Event.new
e.schedule = s
it seems to serialize and deseralize as I would expect, and I can call things like
e.schedule.occurs_at?(Date.today + 1.day)
and get the expected response. However, if I try:
e.schedule.add_recurrence_rule Rule.daily
instead of calling it on the local variable s
before setting the property on event
, I can look at the hash and see the rule is not persisted.
Is there something I'm missing on the right way of doing this sort of thing in Ruby or Mongoid?
I tried using write_attribute and read_attribute, but that was likewise to no avail.
解决方案
While not the most pretty, this strategy will work:
class Event
include Mongoid::Document
validates_presence_of :title
field :title, type: String
field :description, type: String
field :schedule
before_save do
write_attribute(:schedule, @schedule.to_yaml)
end
def schedule=(s)
@schedule = s
end
def schedule
@schedule ||= begin
yaml = read_attribute(:schedule)
yaml ? IceCube::Schedule.from_yaml(yaml) : IceCube::Schedule.new
end
end
end
其他提示
Roman's solution requires an additional step to serialize the recurrence rules. You need to write the instance variable @schedule to the attributes hash once you've added the rule.
In my code it's used something like this:
before_save :serialize_schedule
def schedule=(s)
super(s.to_yaml) if s.is_a?(IceCube::Schedule)
end
def schedule
yaml = super()
if yaml.nil?
@schedule ||= IceCube::Schedule.new(Time.at(0))
else
@schedule ||= Schedule.from_yaml(yaml)
end
end
def serialize_schedule
self.schedule = schedule
end
When I send it the params hash from a form:
def repeats_weekly_days=(day_array)
schedule.add_recurrence_rule IceCube::Rule.weekly.day(day_array.map(&:to_sym))
serialize_schedule
end
The following test passes:
describe "#assign_attributes" do
let(:params) {{start_time: "08:00", end_time: "12:00", repeats_weekly_days: ["monday", "thursday"]}}
it "expect schedule to repeat on Mondays and Thursdays" do
jc.assign_attributes(params)
expect(jc.read_attribute(:schedule)).to include('WeeklyRule')
expect(jc.schedule.recurrence_rules[0].to_s).to eq('Weekly on Mondays and Thursdays')
end
end
It's not a particularly elegant solution but it works.