|
Passing url variables through Isapi re write - Regular Expression |
One of the more common tasks in ColdFusion development is passing variables through the URL string. We are all familiar with the idea that the question mark (?) denotes the url query string start, and that name value pairs are separated with the ampersand (&).
I usually avoid using this in display templates, as it isn't great exposing your internal site workings to customers, and with Fusebox it is very easy to pass the URL variables to an "act_" template and remain hidden.
What happens when you want to use dynamic url variables with a URL re writing application like Isapi re write? I've been using Isapi re write in some FuseBox framework application, and it is relatively easy to set up a rewrite rule, as shown below.
Where the url /home/ would actually serve up the content specified in the fuse specified. But this is hard coded. What about dynamic variables?
We can create a regular expression to handle the translation of the variables.
We use a similar URL, but append the dollar ($) 1 = dollar ($) 2 string. In the re write rule we specify that appended variables are transposed into the string using the slash (/) as a separator.
So as an example we could pass a product id of 24 into the rule like this:
2RewriteRule buy/(.*)/(.*)/ index.cfm?go=cart.buy&$1=$2
It would be rewritten to the more familiar url string. A handy way of continuing to mask the url.
|
Using Coldfusion to generate JQuery validation scripts |
In this article I am exploring the idea of automatically creating JQuery validation from a simple Coldfusion input. In this case a list of required fields. I'll say up front Ray Camden's blog entry on Jquery Validation (http://www.coldfusionjedi.com/index.cfm/2009/2/10/An-Introduction-to-jQuery-and-Form-Validation-2) has been an invaluable help.
The principle behind this is that you can create a generic validation object routine, and simple provide it with a set data object (list or struct, haven't decided yet) and have it match against a form and validate it. So with that in mind we will create a simple form.
2
3<label for="name">Name</label><br/>
4<input type="text" name="name" id="name" class="form-field"><p/>
5
6<label for="telephone">Telephone</label><br/>
7<input type="text" name="telephone" id="telephone" class="form-field"><p/>
8
9<label for="email">Email</label><br/>
10<input type="text" name="email" id="email" class="form-field"><p/>
11
12<label for="favouriteSandwhich">Favourite Sandwhich</label><br/>
13<input type="text" name="favouriteSandwhich" id="favouriteSandwhich" class="form-field"><p/>
14
15<input type="submit" name="action" value="Submit">
16
17</form>
2<scr/ipt type="text/javascript" src="jquery.validate.pack.js"></script>
2 $(document).ready(function(){
3 $("#form").validate({
4
5 errorContainer: "#error",
6 errorLabelContainer: "#error ul",
7 wrapper: "li",
8
9 rules: {
10 <cfoutput>
11 <cfloop list="#variables.requiredList#" index="variables.index">
12 #variables.index#: {required: true <cfif findNoCase('email', variables.index, '1')>, email: true</cfif>, minlength: 5},
13 </cfloop>
14 </cfoutput>
15 },
16
17 messages: {
18
19 <cfoutput>
20 <cfloop list="#variables.requiredList#" index="variables.index">
21 #variables.index#: {required: "The #variables.index# field is required",
22 <cfif findNoCase('email', variables.index, '1')> email: "Email addresses are of the form user@host. Please enter a valid email address.",</cfif>
23 minlength: jQuery.format("You need to use at least {0} characters for your name.")
24 },
25
26 </cfloop>
27 </cfoutput>
28
29 }
30 }
31 );
32 });
33 </script>
2/* Error handling styles */
3#error {-moz-background-clip:border;
4 -moz-background-inline-policy:continuous;
5 -moz-background-origin:padding;
6 background:#FFE7DF;
7 background-position: 5px 8px;
8 border: #FF3F00 solid 1px;
9 color:#440000;
10 margin:10px 0 1em;
11 padding:0px 7px 7px 7px;
12 display:none;
13 width: 90%;}
14
15/* padding for the list */
16#error ul {list-style-type:none; padding: 0px 0px 0px 0px;}
17
18/* padding for the list items */
19#error ul li {padding: 4px 0 2px 16px;}
20
21.error {color: red; list-style-type:none; padding: 0px 0px 0px 0px; width: 198px; color:#440000; background:#FFE7DF;}
22li {list-style-type:none;}
23.form-field {width: 200px; padding: 0px 0px 0px 0px;}
24</style>
This creates a totally dynamic validation routine - all fed from a list. I think it forms a good basis to build a more dynamic rules driven model, where you can set field lengths as well.
There is an example of the complete code here, along with a variation on the inline or external placing of the validation messages.
|
Using Isapi rewrite to serve up non existing templates |
I was discussing some ideas for an application framework this morning with the team, and one of the issues we hit upon was having a common directory for templates, but serving them up as if they were from a different directory.
The idea is to have one instance of a reusable skinnable template, that appears to live on several sites.
IE all the content lives in "webroot/content/templateName.cfm", but is actually served up by many sites, IE "127.0.0.1/site1/template1.cfm", "127.0.0.1/site2/template1.cfm" ... etc
In this way they can be re skinned or adapted as needed, and they aren't database driven. The main stumbling block for the discussion was the need to actually create blank versions of each of the named templates, in each of the sites, as ColdFusion server would error on the request.
I spent twenty minutes trying to work it so that my Application.cfc's onRequest or onRequestStart method would intercept the request before it was actually made, but that just wasn't working. My other idea was to use the onMissingTemplate method, but the server is only running ColdFusion 7, so that was a no go (I figured I could catch the missing template request and just re path it, although I'd have to assess if that was really inefficient due to almost every page request logging as failed).
My eventual solution was Isapi rewrite. I am re writing all the requests to the same template, and just passing in the template variable. In that way I can request pages that don't actually exist, but they appear in the url.
Create an index.cfm template like this:
2<ul>
3 <li><a href="page1">Page 1</a></li>
4 <li><a href="page2">Page 2</a></li>
5 <li><a href="page3">Page 3</a></li>
6 <li><a href="page4">Page 4</a></li>
7</ul>
8
9<cfdump var="#url#">
10<!--- write a handler to go get the url var passed in --->
For this example I am using the free version of Helicon's Isapi rewrite, you can get it here: Link to Helicons Isapi re write
In the example below I have altered the first page link to look like it is actually a .cfm template request, just in case you want the url string to have a .fileextension look to it.
2# Version 3.1.0.68
3
4RewriteEngine on
5RewriteBase /mywebroot
6
7#no physical page testing
8RewriteRule page1.cfm(/)? isapitest/index.cfm?p=page1
9RewriteRule page2(/)? /index.cfm?p=page2
10RewriteRule page3(/)? /index.cfm?p=page3
11RewriteRule page4(/)? /index.cfm?p=page4
So when you fire it up and test it you just see /page1, /page2 etc, and the pages don't actually exist.
I'm not experienced enough with Isapi rewrite to know if there is a downside to this, but bookmarking in a browser still works correctly, so I can't see an issues at present.
|
Image expired error message using CFChart |
A bug came up in an application that uses the CFchart tag to create flash charts.
On the initial load the charts display just fine, but if you refresh the page, or go back to it later to view the data the images error. They display like this:
There seem to be two potential reasons for this. The first is that the cache for the chart in ColdFusion has expired. It seems that by default the per request cache is for 5 seconds only, so if your template takes longer than this to run then you may end out with expired content before you serve it up.
To fix this try this, excerpt from the CFchart blog:
1. Stop the CF server.
2. Open
2<server image="PNG" cache="Memory" minTimeout="5000" maxTimeout="30000"....
Change this to whatever values you want.(Values of minTimeout and maxTimeout are in milliseconds.)
Full article here: http://cfchart.blogspot.com/2005/06/image-expired-trouble.html
The second potential reason for this, and the more likely in this case is that the code is running on a clustered server. The error is cause where the CFchart tag generates a temporary file (swf, png, jpg) and serves that up to the user. When the user makes another request there is no guarantee that the request will hit the same server, so it will not find the temporary file, and throws the 'content expired' error message.
You could ensure that the content is served up correctly by tying the user to the server using session management, or more ideally set the temporary file to be written to a central server in a kind of CDN (Content Distributed Network) way.
I'm off to try both and see which one works!