Ask Ben: Building A jQuery And ColdFusion Rating System

<!--- Query for images to rate. --->
<cfquery name="image" datasource="#application.dsn#">
	SELECT
		i.id,
 
		<!--- Get the current rating for the image. --->
		(
			CASE
				WHEN
					COUNT( r.rating ) > 0
				THEN
					(
						SUM( r.rating ) /
						COUNT( r.rating )
					)
				ELSE
					0
			END
		) AS rating,
 
		<!--- Query for existing rating by user. --->
		COALESCE( er.id, 0 ) AS has_existing_rating
	FROM
		(
			SELECT 1 AS id UNION ALL
			SELECT 2 AS id UNION ALL
			SELECT 3 AS id
		) AS i
 
	<!--- Join this to the rating table to get rating. --->
	LEFT OUTER JOIN
		rating r
	ON
		i.id = r.image_id
 
	<!---
		Join this to the rating table AGAIN to see if the current
		user has already rated the given image.
	--->
	LEFT OUTER JOIN
		rating er
	ON
		(
				er.image_id = i.id
			AND
				er.ip_address = <cfqueryparam value="#cgi.remote_addr#" cfsqltype="cf_sql_varchar" />
			AND
				er.user_agent = <cfqueryparam value="#cgi.http_user_agent#" cfsqltype="cf_sql_varchar" />
		)
 
	GROUP BY
		i.id,
		r.image_id
	ORDER BY
		i.id ASC
</cfquery>
 
 
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
	<title>jQuery And ColdFusion Rating System Demo</title>
	<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
	<script type="text/javascript">
 
		// Define jquery plugin.
		jQuery.fn.rating = function( postUrl ){
			// Loop over each list to apply meta data.
			this.each(
				function( index, listNode ){
					var list = $( this );
					var metaData = list.find( "script.meta-data" );
 
					// Check to see if meta data was found.
					if (metaData.size()){
 
						// Apply meta data.
						list.data(
							"metaData",
							eval( "(" + metaData.text() + ")" )
							);
 
						// Remove the meta data node.
						metaData.remove();
 
					}
				}
				);
 
 
			// Initialize the links within the list.
			this.find( "a" )
				.attr( "href", "javascript:void( 0 )" )
				.click(
					function( clickEvent ){
						var link = $( this );
						var list = link.parents( "ul:first" );
						var metaData = list.data( "metaData" );
 
						// Post the rating.
						jQuery.ajax({
							type: "post",
							url: postUrl,
							data: {
								image_id: metaData.id,
								rating: link.text()
								},
							dataType: "json",
							success: function( apiResponse ){
								// Check to see if the API request
								// was valid.
								if (apiResponse.SUCCESS){
 
									// Replace the list with the
									// current rating.
									list
										.empty()
										.append(
											"<li>Rating: " +
											apiResponse.DATA.toFixed( 1 ) +
											"</li>"
											)
									;
 
								}
							}
							});
 
						// Cancel default event.
						return( false );
					})
			;
 
			// Return jQuery object for chaining.
			return( this );
		};
 
 
		// When the DOM is ready, initialize the plugin.
		$(function(){
			$( "ul" ).rating( "rate_image.cfm" );
		});
 
	</script>
	<style type="text/css">
 
		ul.rating {
			height: 20px ;
			list-style-type: none ;
			margin: 10px 0px 0px 0px ;
			padding: 0px 0px 0px 0px ;
			}
 
		ul.rating li {
			float: left ;
			margin: 0px 5px 0px 0px ;
			padding: 0px 0px 0px 0px ;
			}
 
		ul.rating a {
			background-color: #F0F0F0 ;
			border: 1px solid #333333 ;
			color: #333333 ;
			float: left ;
			height: 20px ;
			line-height: 20px ;
			text-align: center ;
			text-decoration: none ;
			width: 20px ;
			}
 
	</style>
</head>
<body>
 
	<h1>
		jQuery And ColdFusion Rating System Demo
	</h1>
 
	<cfoutput>
 
		<cfloop query="image">
 
			<div style="float: left ; margin-right: 20px ;">
 
				<img
					src="./images/girl#image.id#.jpg"
					width="165"
					style="display: block ;"
					/>
 
				<!--- Check to see if user has rated yet. --->
				<cfif image.has_existing_rating>
 
					<!---
						User has already rated, just show the
						current rating.
					--->
					<ul class="rating">
						<li>
							Rating: #numberFormat(
								image.rating,
								"0.0"
								)#
						</li>
					</ul>
 
				<cfelse>
 
					<!--- Show the rating options. --->
					<ul class="rating">
						<!---
							Set up the meta-data for this image.
							This data will be applied when the
							rating plugin is initialized.
						--->
						<script
							type="application/x-json"
							class="meta-data">
							{
								id: #image.id#
							}
						</script>
						<li>
							<a>1</a>
						</li>
						<li>
							<a>2</a>
						</li>
						<li>
							<a>3</a>
						</li>
						<li>
							<a>4</a>
						</li>
					</ul>
 
				</cfif>
 
			</div>
 
		</cfloop>
 
	</cfoutput>
 
</body>
</html>

For Cut-and-Paste