mhgbrown / cached_resource

Caching for ActiveResource
MIT License
80 stars 28 forks source link

Storing objects as json in cache breaks persistence #42

Closed vibro closed 5 years ago

vibro commented 5 years ago

I recently updated to 5.1.0 after experiencing the problems that #40 fixed. However, I tried updating an object I had retrieved from the cache, and the persistence field is missing. This means instead of calling update, ActiveResource called create on the object.

I tried calling find with reload => true, but it looks like it writes to the cache and then reads from there, causing the same problem.

Old Behavior (5.0.1):

Cache read: my_active_resource/123
Dalli::Server#connect 127.0.0.1:11211
Cache write: my_active_resource/123 ({:race_condition_ttl=>86400, :expires_in=>604800})
[cached_resource] WRITE my_active_resource/123
Cache read: my_active_resource/123
[cached_resource] READ my_active_resource/123
 => #<MyActiveResource:0x007fb59e0ba8c8 @attributes={"id"=>123}, @prefix_options={}, @persisted=true> 
2.3.1 :005 > m.persisted?
 => true 

New behavior:

Cache read: my_active_resource/123
Dalli::Server#connect 127.0.0.1:11211
Cache write: my_active_resource/123 ({:race_condition_ttl=>86400, :expires_in=>604800})
[cached_resource] WRITE my_active_resource/123
Cache read: my_active_resource/123
[cached_resource] READ my_active_resource/123
 => #<MyActiveResource:0x007fab706a1f58 @attributes={"id"=>123 }, @prefix_options={}, @persisted=false> 
2.3.1 :002 > m.persisted?
 => false 

Is there a way to keep persistence? Or stop reading directly from the cache in instances where I want to update?

Daniel-ltw commented 5 years ago

Could you debug this issue and try to also include the prefix_options and the persisted into the json?

vibro commented 5 years ago

I think I was able to solve it by adding persisted:

def cache_write(key, object)
  if object.is_a? Enumerable
    json = object.map { |o| { object: o.to_json, persistence: o.persited? } }.to_json
  else
    json = { object: object.to_json, persistence: object.persited? }.to_json
  end
  result = cached_resource.cache.write(key, json, :race_condition_ttl => cached_resource.race_condition_ttl, :expires_in => cached_resource.generate_ttl)
  result && cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} WRITE #{key}")
  result
end

def json_to_object(json)
  if json.is_a? Array
    json.map { |attrs| self.new(attrs[:object], attrs[:persistence]) }
  else
    self.new(json[:object], json[:persistence])
  end
end

If this is the right direction, happy to open a PR for it.

Daniel-ltw commented 5 years ago

Did the instantiation of the object work?

That all looks like it is the right direction. Feel free to create a pull request.

mhgbrown commented 5 years ago

@Daniel-ltw 💪for being on top of this. I'll make a new release with https://github.com/mhgbrown/cached_resource/pull/43 soon.

mhgbrown commented 5 years ago

published in 5.1.1 https://rubygems.org/gems/cached_resource/versions/5.1.1

Daniel-ltw commented 5 years ago

@mhgbrown @vibro did all the work. Kudos to @vibro

mhgbrown commented 5 years ago

Absolutely. I just mean you acting as a "face" of cached_resource.

Daniel-ltw commented 5 years ago

Happy to help out a fellow developer as and when I can.

vibro commented 5 years ago

Thanks everyone!