CF9 ORM and Apache’s mod_rewrite
Here’s another problem I’ve run into with ColdFusion’s ORM (there seem to be a few of these recently…).
I’ve only just started running a CF dev environment under Apache on my Mac – I was previously running IIS under VMWare. The problem comes when using Apache’s mod_rewrite for URL rewriting.
I set up a simple test scenario with the following Application.cfc:
component output="false"
{
this.name = "ormtest";
this.sessionManagement = true;
this.sessiontimeout = CreateTimeSpan(0,5,0,0);
this.ormEnabled = true;
this.datasource = "TEST";
this.ormSettings = {
cfclocation = "/model"
};
}
The model directory contains a single ORM mapping bean, user.cfc.
This runs fine and initialises without a problem. But then I add the following mod_rewrite rules into .htaccess:
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !/(assets|index.cfm) [NC]
RewriteRule ^(.*)$ /index.cfm/$1 [NC,L]
This handles rewriting of SES URLs for FW/1 pages – essentially, anything that’s not in the assets folder gets index.cfm/ prepended to it behind the scenes. However, this causes the following error when loading the application:
Could not find the ColdFusion component or interface user.
It turns out that the reference to /model as the ORM’s cfclocation is also being rewritten; what is more, adding model into the RewriteCond of paths to ignore doesn’t solve the problem.
After a bit of searching, I discovered Richard Herbert had experienced what seemed to be the same problem. A quick tweet later, and he told me of the solution he’d found.
The solution is simple: create a mapping to the directory containing the ORM CFCs. So, in my example, I added the following before the ORM settings:
this.mappings = {'/model' = '/Volumes/Dev/Web/sites/ormtest/model'};
…and everything now works as it should. (Note: be sure to change the mapping to reflect the structure of your live server!)
Out of interest, I tried the same test under IIS running ISAPI_Rewrite – and it didn’t share the problem. So I assume that mod_rewrite runs at a lower level in the system than ISAPI_Rewrite: mod_rewrite will rewrite your internal CF file calls. So that’s something to be wary of…
Without knowing your whole setup I can't say for sure, but I'd be willing to bet the source of your problem actually has nothing to do with mod_rewrite since CF wouldn't even be hitting your web server to find the CFC.
I bet you're running this application in a subdirectory of a virtual host's root, meaning you're accessing it via http://host/appdirectory as opposed to just http://host
This would create a need for a mapping to model since /model (or CreateObject('component', 'model.whatever') for that matter) would be looking for model to be in the host's root. Since it's not, you'd either have to access it differently (/appdirectory/model as opposed to just /model) or create a mapping as you've done.
In short, I'd be shocked if mod_rewrite has anything to do with the issue you're describing since the web server isn't even involved at that level.
Matt,
1. The site is running at the root of the virtual directory. I always set every site up as it's own virtual host, since that's how it will exist on the live server.
2. If I remove the mod_rewrite commands, the site works perfectly even without the mapping.
Any ideas?
Well, I've never used CF 9 so I can't speak to how it works, but it's surprising that it would in any way be interacting with your web server.
I still suspect something else is afoot, particularly since a *mapping* fixes the issue, since Apache wouldn't know anything about the mapping. So it sounds like you're saying you suspect the problem is with a rewrite rule on the Apache side, yet you're fixing it with a mapping on the CF side? Doesn't make logical sense to me.
As I said though, I don't use CF 9 or the ORM tool so for all I know there's something going on with things at that level. Based on my experience with Apache and mod_rewrite, however, it just seems like there has be something else at play here, but ultimately whatever fixes it fixes it I suppose.
I'd be curious if WITHOUT the mapping in place but WITH the rewrite rule in place you can do this:
<cfset user = CreateObject('component', 'model.user') />
If you don't get a component not found error with that, then there's definitely something going on at the ORM level in terms of how it looks for things.
OK, I've tried the basic component creation you suggested above. I disabled ORM, disabled the mapping, but left the rewrite rule in place.
The object is created without a problem, so there defeinitely seems to be something going on with ORM...
Also, running another test on my original example, if my RewriteCond includes "model" as a path to be ignored by the rule, I get the message originally stated; but if I take "model" out of the RewriteCond (i.e. so a request to "/model/whatever" will be rewritten), I get the error:
"Path /model specified in the cfclocation does not exist."
(Note I need to restart the CF server for each test, as once it's found the cfcocation once, it remembers it even if I change mappings etc.)
So it seems that mod_rewrite is definitely coming in to play with the ORM calls...
Very bizarre. Wouldn't have expected that behavior!
No. I didn't expect it either!