Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created March 25, 2014 10:46
Show Gist options
  • Save bennadel/9759096 to your computer and use it in GitHub Desktop.
Save bennadel/9759096 to your computer and use it in GitHub Desktop.
Ask Ben: Building A jQuery And ColdFusion Rating System
<!--- Create a unified API resposne. --->
<cfset apiResponse = {
success = true,
errors = [],
data = ""
} />
<!--- Try to execute the api request / response. --->
<cftry>
<!--- Param the FORM variable. --->
<cfparam name="form.image_id" type="numeric" />
<cfparam name="form.rating" type="numeric" />
<!---
Check to see if this user has already rated this image.
We do not want to allow duplicate ratings.
--->
<cfquery name="existingRating" datasource="#application.dsn#">
SELECT
r.id
FROM
rating r
WHERE
r.image_id = <cfqueryparam value="#form.image_id#" cfsqltype="cf_sql_integer" />
AND
r.ip_address = <cfqueryparam value="#cgi.remote_addr#" cfsqltype="cf_sql_varchar" />
AND
r.user_agent = <cfqueryparam value="#cgi.http_user_agent#" cfsqltype="cf_sql_varchar" />
</cfquery>
<!--- Check to see if the rating exists. --->
<cfif existingRating.recordCount>
<!--- Add error. --->
<cfset arrayAppend(
apiResponse.errors,
"You have already rated this image."
) />
</cfif>
<!--- Check to see if we have any errors. --->
<cfif NOT arrayLen( apiResponse.errors )>
<!--- Insert new rating. --->
<cfquery name="insertRating" datasource="#application.dsn#">
INSERT INTO rating
(
ip_address,
user_agent,
rating,
date_created,
image_id
) VALUES (
<cfqueryparam value="#cgi.remote_addr#" cfsqltype="cf_sql_varchar" />,
<cfqueryparam value="#cgi.http_user_agent#" cfsqltype="cf_sql_varchar" />,
<cfqueryparam value="#form.rating#" cfsqltype="cf_sql_integer" />,
<cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp" />,
<cfqueryparam value="#form.image_id#" cfsqltype="cf_sql_integer" />
);
<!--- Get the new overall rating. --->
SELECT
(
SUM( r.rating ) /
COUNT( r.rating )
) AS overall_rating
FROM
rating r
WHERE
r.image_id = <cfqueryparam value="#form.image_id#" cfsqltype="cf_sql_integer" />
;
</cfquery>
<!--- Set the current rating as the response data. --->
<cfset apiResponse.data = insertRating.overall_rating />
</cfif>
<!--- Catch any api errors. --->
<cfcatch>
<!--- Set the error in our api response object. --->
<cfset apiResponse.errors = [ cfcatch.message, cfcatch.detail ] />
</cfcatch>
</cftry>
<!--- Check to see if we have any errors at this point. --->
<cfif arrayLen( apiResponse.errors )>
<!--- Flag the API request as unsuccessful. --->
<cfset apiResponse.success = false />
</cfif>
<!--- Searialize the API response into our JSON value. --->
<cfset jsonResponse = serializeJSON( apiResponse ) />
<!--- Convert the response string to binary for streaming. --->
<cfset binaryResponse = toBinary( toBase64( jsonResponse ) ) />
<!--- Stream the binary data back. --->
<cfheader
name="content-length"
value="#arrayLen( binaryResponse )#"
/>
<cfcontent
type="text/x-json"
variable="#binaryResponse#"
/>
<!--- 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>
<cfcomponent
output="false"
hint="I define the application settings and event handlers.">
<!--- Define the application. --->
<cfset this.name = hash( getCurrentTemplatePath() ) />
<cfset this.applicationTimeout = createTimeSpan( 0, 0, 5, 0 ) />
<!--- Define the page request settings. --->
<cfsetting showdebugoutput="false" />
<cffunction
name="onApplicationStart"
access="public"
returntype="boolean"
output="false"
hint="I initialize the application.">
<!--- Define the application. --->
<cfset application.dsn = "xyz" />
<!--- Return out. --->
<cfreturn true />
</cffunction>
</cfcomponent>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment