nesquena / rabl

General ruby templating with json, bson, xml, plist and msgpack support
http://blog.codepath.com/2011/06/27/building-a-platform-api-on-rails/
MIT License
3.65k stars 335 forks source link

Caching Bugs - Corrupted/overwritten keys. Values that throw errors when fetched #424

Open andrewhubbs opened 11 years ago

andrewhubbs commented 11 years ago

I am running into a pretty strange bug with caching RABL views.

I have a setup that looks something like this:

Relevant Config

# rabl_config.rb
Rabl.configure do |config|
  config.cache_all_output = true
  config.cache_sources = Rails.env != "development"
  config.include_json_root = false
  config.view_paths = [Rails.root.join("app/views")]
end

# relevant portions of Gemfile
ruby "2.0.0"

gem "rails", "3.2.13rc1"
gem "oj"
gem "rabl", "0.8.0"

Views

# employees/limited_show.rabl
object @employee
cache ["limited", root_object]
attributes :id, :name

# employees/show.rabl
object @employee
cache ["full", root_object]
attributes :secret_stuff
node do |employee|
  partial "employees/limited_show", object: employee
end
#...

# employees/index.rabl
collection @employees
extends "employees/show"

# companies/show.rabl
object @company
attributes :name
node :employees do |company|
  partial "employees/index", object: company.employees.active
end
#...

Note: Except for the two employee show views, I use the default cache keys throughout.

Controllers

# companies_controller.rb
def show
  @company = Company.find(params[:id])
end

# employees_controller.rb
def show
  @employee = Employee.find(params[:id])
  render "employees/#{current_user.admin? ? "" : "limited_"}show"
end

When I hit the companies#show controller, I expect/get cache keys like the following:

"rabl/companies/1-20130320204732//json"
"rabl/full/employees/2-20130320165909//hash"
"rabl/limited/employees/2-20130320165909//hash"

I am also getting additional cache keys on companies#show that I'm not expecting that look like this:

"rabl/employees/1-20130320204732//hash"

Does the collection view generate additional cache values other than the ones normally created by the view it extends?

When I hit the employees#show controller, I expect/get cache keys like the following (depending on user permissions):

"rabl/full/employees/2-20130320165909//hash"
"rabl/limited/employees/2-20130320165909//hash"
"rabl/full/employees/2-20130320165909//json"
"rabl/limited/employees/2-20130320165909//json"

Everything basically works when I visit either of those routes _independently_. Weird things happen when I visit _one route after the other_.

For instance, after loading the companies#show I will have the 3 cache keys above, and as expected they have different values:

Rails.cache.fetch("rabl/full/employees/2-20130320165909//hash") == Rails.cache.fetch("rabl/limited/employees/2-20130320165909//hash")
> false

but, if I then visit the employees#show, those cached values are _the same_.

Rails.cache.fetch("rabl/full/employees/2-20130320165909//hash") == Rails.cache.fetch("rabl/limited/employees/2-20130320165909//hash")
> true

It is like calling the show template directly and creating the JSON cached version is corrupting the hash version (which should only be getting read and not written anyways).

Furthermore, I am also getting spurious exceptions like ArgumentError (undefined class/module Team): when I fetch some keys from the cache.

Basically, if I hit the companies#show everything is fine and loads correctly. I can make changes and my expiration code works great as well. If I then hit the employees#show it also works fine and returns the correct data. _But_, when I hit the companies#show again _after_ the employees#show I get back _incorrect data for employees_ that excludes changes and excludes all additional partials from the employees/show.rabl that are attached as nodes. Both calls are read only and will always happen even if there are no changes to any DB records/cache invalidations between them. I am at a loss here for what is happening.

Any thoughts on what might be going on?

andrewhubbs commented 11 years ago

It feels like there are probably 2 or 3 different bugs here:

andrewhubbs commented 11 years ago

@nesquena, why are all of the bugs about caching with RABL being ignored (there are at least 3 issues open)? I think caching is pretty important to RABL and there are likely some very serious bugs in it.

I am happy to help out but some guidance on what RABL is doing here would be helpful.

nesquena commented 11 years ago

Sorry, don't mean to ignore caching bugs, honestly I am a bit overstretched right now working on too many different things. RABL Caching was originally implemented by @databyte and other contributors so it is not the first thing I reach towards when I want to put a little time into RABL. Also, it's not a huge personal pain I'm feeling on my own rabl projects at the moment but I fully recognize it's importance. If anyone else can help submit patches for caching, I am more then happy to review and apply. If I missed any then please let me know.

nesquena commented 11 years ago

Speaking of which, take a look at #417 and see if that would help address any of the issues?