I'm getting weird behavior when I try to save an object in memory to the database and then cache that object with Dalli.
class Infraction << ActiveRecord::Base
has_many :infraction_locations
has_many :tracked_points, through: :infraction_locations
end
class TrackedPoint << ActiveRecord::Base
has_many :infraction_locations
has_many :infractions, through: :infraction_locations
end
class InfractionLocation << ActiveRecord::Base
belongs_to :infraction
belongs_to :tracked_point
belongs_to :rule
end
This works:
i = Infraction.create
i.tracked_points << TrackedPoint.create(location_id: 1)
i.save
Rails.cache.write "my_key", i
This also works:
i = Infraction.new
i.tracked_points << TrackedPoint.create(location_id: 1)
i.save
Rails.cache.write "my_key", i
Notice that the objects (in the second case just the TrackedPoint
), is saved to the database implicitly by the call to create.
I've also found that reloading i
allows me to write the object to the cache. So this works:
i = Infraction.new
i.tracked_points << TrackedPoint.new(location_id: 1)
i.save
i.reload
Rails.cache.write "my_key", i
This fails:
i = Infraction.new
i.tracked_points << TrackedPoint.new(location_id: 1)
i.save
Rails.cache.write "my_key", i
However, if I do some weird duping, I can get the failing example to work:
i = Infraction.new
i.tracked_points << TrackedPoint.new(location_id: 1)
i.save
copy = i.dup
copy.tracked_points = i.tracked_points.to_a
Rails.cache.write "my_key", copy
In my failing example, I can cache the infraction (i
) before I save it to the database, like this:
i = Infraction.new
i.tracked_points << TrackedPoint.new(location_id: 1)
Rails.cache.write "what", i
Per Dave's idea, I tried build
instead of <<
for the TrackedPoint
as well as adding a accepts_nested_attributes_for :tracked_points
to Infraction
, but neither of those worked.
I am getting the marshalling/serializer error in the log:
You are trying to cache a Ruby object which cannot be serialized to memcached.
I am running Rails 3.2.13 and Dalli 2.7.0
EDIT
See also: Cacheing an ActiveRecord Object that has_many through:
Turns out it was a problem with squeel.
There is something called an AliasTracker that is not being Marshalled correctly. A monkey patch that appears to fix this issue is:
module ActiveRecord
module Associations
class AliasTracker
def marshal_dump(*)
nil
end
def marshal_load(*)
nil
end
end
end
end
More discussion and answer from here: https://github.com/activerecord-hackery/squeel/issues/232