序列化Mongoid的IceCube对象

时间:2012-10-10 12:21:06

标签: ruby-on-rails mongoid ice-cube

我发现这篇文章:Override a Mongoid model's setters and getters来帮助我,但行为仍然不是我想要的。

我的模型是这样的:

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

这或多或少都像我期望的那样,因为它序列化和反序列化IceCube对象,但是我注意到的是,虽然我可以这样做:

s = Schedule.new(Time.now)
s.add_recurrence_rule Rule.daily
e = Event.new
e.schedule = s

它似乎按照我的预期进行序列化和解除分类,我可以调用类似

的内容
e.schedule.occurs_at?(Date.today + 1.day) 

并获得预期的回复。但是,如果我尝试:

e.schedule.add_recurrence_rule Rule.daily

而不是在s上设置属性之前在局部变量event上调用它,我可以查看哈希并看到规则不会保留。

在Ruby或Mongoid中做这种事情的正确方法是否存在我缺少的东西?

我尝试使用write_attribute和read_attribute,但这同样无济于事。

2 个答案:

答案 0 :(得分:2)

虽然不是最漂亮的,但这个策略可行:



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

答案 1 :(得分:0)

Roman的解决方案需要一个额外的步骤来序列化重复规则。在添加规则后,您需要将实例变量@schedule写入属性哈希。

在我的代码中,它使用了这样的东西:

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

当我从表单发送params哈希时:

def repeats_weekly_days=(day_array)
  schedule.add_recurrence_rule IceCube::Rule.weekly.day(day_array.map(&:to_sym))
  serialize_schedule
end

以下测试通过:

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

这不是一个特别优雅的解决方案,但它有效。