开发者

Problem with Rails page caching and automatic extensions

I have a JSON and XML based API that needs to be page cached. I have setup my routes on the api to include the format as part of the URL, such that URL's like this work:

http://example.com/foo/1/bar/2/xml
http://example.com/foo/1/bar/2/json

The problem I am seeing is that in the server's public folder, the files are being saved as xml.xml and json.json, and this causes cache misses the next time the URL is accessed.

Is there a way to either:

  1. Turn off the auto extension generation so that they are saved without an extension at all? (EX: RAILS_ROOT/public/foo/1/bar/2/json)
  2. Force all the extensions to be .html for every call. (EX: RAILS_ROOT/public/foo/1/bar/2/json.html)

Either of these would cause my server to return the cached file instead of a miss. How can I do this?

EDIT:

Somebody asked for the relevant route:

scope '(foo/:foo_id)', :foo_id => /\d+/ do
  get '/bar/:bar_id/:format' => 'bars#show', :bar_id => /\d+/, :format => /json|xml|html/
end

SOLUTION:

While I was looking for an official way to make this happen开发者_高级运维 using the built in page caching support, I ended up just using an after filter and my own page cache method, as suggested by Anton

# application_controller.rb
def cache_api_page
  if REDACTEDServer::Application.config.action_controller.perform_caching
    self.class.cache_page(response.body, request.path, '')
    puts "CACHED PATH: #{request.path}"
  end
end

# bar_controller.rb
 after_filter :cache_api_page, :only => [ :show, :index ]


You can do that like this:

class FooController < ApplicationController

  after_filter(:only => :show, :if => Proc.new { |c| c.request.format.json? }) do |controller|
    controller.class.cache_page(controller.response.body, controller.request.path, '.html')
  end

end

When http://example.com/foo/1/bar/2/json is accessed, it will write page to cache (RAILS_ROOT/public/foo/1/bar/2/json.html)

And if you get http://example.com/foo/1/bar/2/json again, you receive RAILS_ROOT/public/foo/1/bar/2/json.html, but your http server(Apache?) should know about content type of this files.

Otherwise content type will set to 'text/html'

UPDATE

To you .htaccess

<FilesMatch "\/json$">
<IfModule mod_headers.c>
  Header set Content-Type "text/json"
</IfModule>
</FilesMatch>


<FilesMatch "\/xml$">
<IfModule mod_headers.c>
  Header set Content-Type "text/xml"
</IfModule>
</FilesMatch>


In your application.rb configuration block try adding:

config.action_controller.page_cache_extension = '.html'

It should ignore the extension calculated from the request, and always use this. You could also try using this with an empty string instead.

EDIT: actually this won't work because this only sets a default. If the request has an extension (in your case, concluded from :format) it will be used.

I suggest changing :format in your routes to something else, that rails will not give special meaning to, like :fmt. Then rails should not add the extension and default to '.html'.

EDIT2: If you have to use :format you can monkeypatch Rails:

ActionController::Caching::Pages::ClassMethods
  private
  def page_cache_file(path)
    name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/'))
    name << page_cache_extension #unless (name.split('/').last || name).include? '.'
    return name
  end
end

Notice the comment sign I've added before 'unless'. This is the part that overrides the default from my first answer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜