4

How do I expire a fragment in the cache with a file extension (.json) from a another controller?

I am using Rails 3.2.8.

I have two controllers for the same models: /admin/books_controller and /api/books_controller. The admin controller is used to create/update/delete books and requires elevated access. The api/books_controller is used to search/list view details about a book by users. I've attempted to cache the api/books_controller

class Api::BooksController < ApiController
  caches_action :show

  def show    
    @book = Book.find(params[:id])
  end
end

This works great. The first request is slow and the second is fast

Rendered api/books/show.json.rabl (119.7ms)
Write fragment views/localhost:3000/api/books/4.json (1.7ms)
Completed 200 OK in 568ms (Views: 124.2ms | ActiveRecord: 9.5ms)

Read fragment views/localhost:3000/api/books/4.json (0.2ms)
Completed 200 OK in 16ms (ActiveRecord: 2.6ms)

Now, I need to expire the the fragments when the Book is updated or destroyed. I have this:

class Admin::BooksController < AdminController

  def update
    @book.attributes = params[:book]
    if (@book.save)
      expire_action(:controller => 'api/books', :action => 'show', :id => @book.id, :format => 'json')
    end
  end

end

However, this doesn't resolve to the same fragment (the request is an HTML request now, to a different controller):

Started PUT "/admin/books/4" for 127.0.0.1 at 2012-11-08 12:27:11 -0600
Processing by Admin::BooksController#update as HTML
...
Expire fragment views/localhost:3000/api/books/4 (0.1ms)

My API controller with a JSON request reads and writes this fragment:

views/localhost:3000/api/books/4.json

My Admin controller tries to expire this fragment:

views/localhost:3000/api/books/4

How do I expire views/localhost:3000/api/books/4.json from the other controller with a different request format?

This question: rails 3 caching: expire action for named route indicates I could use a regex to expire multiple fragments, but that requires the keys in the cache to be enumerable (http://api.rubyonrails.org/classes/ActionController/Caching/Fragments.html#method-i-expire_fragment)

Community
  • 1
  • 1
John Naegle
  • 8,077
  • 3
  • 38
  • 47
  • Executing the `expire_action` with `:format => 'json'` produces `Expire fragment views/localhost:3000/api/books/4`? Is it the problem? I'm having a hard time clearly understanding what's the issue. – Anthony Alberto Nov 08 '12 at 18:46
  • Yes, I expected it to produce views/localhost:3000/api/books/4.json – John Naegle Nov 08 '12 at 18:47
  • I tried it in my app ... and it works as expected `Expire fragment views/www.example.com/api/books/show/1.json` ... can you try to do an `expire_action` with a `format` param on some very basic action, like your homepage? – Anthony Alberto Nov 08 '12 at 19:08
  • Also try using `expire_fragment` instead with the same params to see if that makes a difference – Anthony Alberto Nov 08 '12 at 19:13
  • It looks like the problem was in my routes: namespace :api, :defaults => {:format => 'json'} do resources :books, :only => [:show] end This caused params[:format] to be set in my api controller, but not in my admin controller. – John Naegle Nov 08 '12 at 19:17

1 Answers1

0

It appears that the problem was with routing setting default parameters. In the API controller, params[:format] was 'json' and in the Admin controller it was nil.

When I added this to my Admin controller:

params[:format] = 'json'
expire_action(:controller => 'api/books', :action => 'show', :id => @book.id, :format => 'json')

Then, the fragments in both controllers matched.

This let me back to my routes:

In my routes I had this:

namespace :api, :defaults => {:format => 'json'} do
  resources :books, :only => [:show]
end

This caused params[:format] to be set in my api namespace. I didn't have anything in my admin namespace and apparently actionpack/ActionCachePath saw these two differently. Removing the defaults in the routes fixed the problem.

John Naegle
  • 8,077
  • 3
  • 38
  • 47