Saturday, August 18, 2007

REST, Caching, and Apache Rewrite problems SOLVED

Problem: Your Rails app is working beautifully in development and test mode, but for some reason, on the production server, users intermittently have trouble POSTing data. It seems like Apache is turning POST requests into GET requests. Looking at the Apache log, you see the POST request come in. Looking at the Rails production log, you see it has been rewritten as a GET request, triggering a "show" or "index" action in your RESTful controller. This may have started when you implemented page caching, but you're not sure. What gives?

Solution: This is a clash between page caching and the Apache rewrite rules. Apache sees that there is a directory in your RAILS_ROOT/public/ directory that matches the name of the URL you are POSTing to, and tries to satisfy the request by serving up content from that directory. You need to change your rewrite rules so that only GET requests for URLs are satisfied with a static file, and all POST requests are delivered to your rails app (to dispatch.fcgi, your mongrel cluster, etc.)

Solution 2: Even if you're not using caching, this problem could also occur if you have a directory in your public/ directory that matches a route in your app (so if you have a route for /assets/, and there's a RAILS_ROOT/public/assets/ directory, you may have the same problem.

Details:

1) Change this following rule in your .htaccess or your Directory directive:

RewriteCond %{REQUEST_FILENAME} !-f

to this:

RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_METHOD} !^GET*

2) I'm not 100% sure this next step is necessary, but I couldn't get it to work otherwise. Add the following directive, IF the caveats in the mod_dir documentation don't apply:

DirectorySlash Off

These two steps will tweak the way Apache views incoming URLs and delivers them to your page_cached, RESTful Rails app.

Other Complications

This bug is hard to track down because it's intermittent, happening only when there are cached pages or a cached directory. On the site where I had this problem, I had a Capistrano task that swept my cached pages whenever I redeployed the app. So you can imagine my agony when I'd make a change, redeploy, the app would work great, then an hour later when pages had been cached, everything stopped working. Argh!

References

This is about 20 hours of my life I'll never get back, so I hope this saves you some pain. The following references were extremely helpful in devising this solution:

Rails mailing list post #1
Rails mailing list post #2
Mephisto wiki

1 comment:

Anonymous said...

Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!