Local Business Reviews Application on a Ruby on Rails Platform

Ruby on Rails Tutorials & Code Examples

Extend rails image_tag to use ALT as TITLE for seo

This code snippet will make code like:
<%= image_tag "rails.png", :alt => 'rails logo' %>

output (with a title tag):
< alt="rails logo" src="/images/rails.png?1182293075">title="rails logo" />

Whack the following somewhere (eg. you could test it by sticking it at the end of environment.rb):

# Extend img tag to use the alt text for the title attribute if alt is present & title is empty (for SEO)
module ActionView::Helpers::AssetTagHelper
alias_method :orig_image_tag, :image_tag
def image_tag(source, options = {})
if options[:alt] && !options[:title]
options[:title] = options[:alt]
end
return orig_image_tag(source, options)
end
end

Labels: , , , ,

Silicon Valley Ruby on Rails January 2007 Meetup

January 2007 Silicon Valley Ruby on Rails Meetup
Last night was the January gathering of the Silicon Valley Ruby on Rails meetup, and it was the best attended and most successful one yet. Brian Hawthorne of likebetter.com and Andre Lewis gave two excellent presentations to a packed room of about 50 Rails enthusiasts. Brian showed us how he used Rails to build likebetter, touching on how they approached template rendering, their use of Amazon's S3 and EC2 web services, and their experience being a Y Combinator funded company. Andre introduced the room to the basics of RESTful routing, just in time for yesterday's release of Rails 1.2. He showed us how to get started using the scaffold_resource generator before diving in to the details of named routes, nested resources and using responds_to to return information in different formats. He also talked about the motivations and benefits of a RESTful approach to writing controllers. Check out his slides here, as well as his excellent blog post about nested CRUD resources.

We'll be doing it again the 3rd Thursday of next month. Hope to see you there.

Get Referring Search Engine Keywords from HTTP_REFERER in Ruby on Rails

Sometimes you may want to customize a page based on a referring search query for the purpose of Adsense optimization, keyword highlighting or custom logging.

A good example of this in action is Google's highlighting of search terms in cached pages and HTML versions of indexed PDF documents eg.

Rails application.rb function:

# Creates @referring_search containing any referring search engine query minus stop words
#
# eg. If the HTTP_REFERER header indicates page referer as:
# http://www.google.com/search?q=Most+Calories+iN+a+Cheesesteak+at+Belmont&start=0&amp;ie=utf-8&oe=utf-8&client=firefox-a&rls=org.mozilla:en-US:official
#
# then this function will create:
# @referring_search = "Most Calories Cheesesteak Belmont"
#
def setup_referring_keywords
# Check whether referring URL was a search engine result
referer = @request.env["HTTP_REFERER"]
unless referer.nil_or_empty?
search_referers = [
[/^http:\/\/(www\.)?google.*/, 'q'],
[/^http:\/\/search\.yahoo.*/, 'p'],
[/^http:\/\/search\.msn.*/, 'q'],
[/^http:\/\/search\.aol.*/, 'userQuery'],
[/^http:\/\/(www\.)?altavista.*/, 'q'],
[/^http:\/\/(www\.)?feedster.*/, 'q'],
[/^http:\/\/search\.lycos.*/, 'query'],
[/^http:\/\/(www\.)?alltheweb.*/, 'q']
]
query_args =
begin
URI.split(referer)[7]
rescue URI::InvalidURIError
nil
end
search_referers.each do |reg, query_param_name|
# Check if the referrer is a search engine we are targetting
if (reg.match(referer))

# Highlight the Search Term Keywords on the page
#@javascripts.push('keyword_highlighter')

# Create a globally scoped variable (@referring_search) containing the referring Search Engine Query
unless query_args.nil_or_empty?
query_args.split("&").each do |arg|
pieces = arg.split('=')
if pieces.length == 2 && pieces.first == query_param_name
unstopped_keywords = CGI.unescape(pieces.last)
stop_words = /\b(\d+|\w|about|after|also|an|and|are|as|at|be|because|before|between|but|by|can|com|de|do|en|for|from|has|how|however|htm|html|if|i|in|into|is|it|la|no|of|on|or|other|out|since|site|such|than|that|the|there|these|this|those|to|under|upon|vs|was|what|when|where|whether|which|who|will|with|within|without|www|you|your)\b/i
@referring_search = unstopped_keywords.gsub(stop_words, '').squeeze(' ')
logger.info("Referring Search Keywords: #{@referring_search}")
return true
end
end
end
return true
end
end
end
true
end

Labels: , ,

Creating & Configuring a Virtual directory Alias in Lighttpd

To configure a virtual directory in Lighttpd , you add an 'alias.url' entry to your lighttpd.conf eg:

lighttpd.conf:

alias.url = ( "/rubyonrails/" => "/shared/published/blogger/" )

Which you would notice is very similar to the Apache Virtual Directory Configuration:

Apache httpd.conf:

    Alias /icons/ "C:/Apache/icons/"


Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all

If you installed Lighttpd without mod_alias, you will probably see:

lighttpd.conf:

2007-01-02 14:45:33: (server.c.871) WARNING: unknown config-key: alias.url (ignored)

This can be fixed by adding a 'mod_alias' entry to your 'server.modules' entry in the lighttpd.conf eg:

lighttpd.conf:

server.modules = ("mod_alias", "mod_rewrite", "mod_redirect")

Labels: , , ,

In-Screen DHTML Modal Dialog with JavaScript DOM & CSS Opacity


From a usability perspective, the advantage of using an internal DHTML dialog (rather than launching a new window or going to a new page - Internet Explorer's showModalDialog() would be a nice solution but it is not cross-browser) is that the interaction with the dialog remains contextually associated with the disabled page. This means for instance, that when your user wants to provide feedback or add detail to a page on your site, this implementation will visually indicate that the dialog element they are interacting with is inherently associated with the disabled page in the background.

From a code-maintainability perspective, this may introduce a code overhead that doesn't justify the usability benefit depending on your web applications implementation framework. It seems rather well suited to an 'AJAX'(y) style application.


This Tip shows how to create, handle & Display an Image or Photo Upload form in Ruby on Rails


DHTML Example:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<title>DHTML Non-clickable protection DIV and in-screen modal dialog style display area using JavaScript DOM using CSS Opaque/Opacity filter</title>

<style type="text/css">
/* http://www.mandarindesign.com/opacity.html */
#internal_dialog { display:none; position:absolute; top:35px; left:150px; z-index:3; background-color:#6495ED; filter:alpha(opacity=100); -moz-opacity:1.00; opacity:1.00; border:3px solid white; margin:auto; color:white; padding:15px; }
.content_faded {filter:alpha(opacity=50); -moz-opacity:.50; opacity:.50; background-color: #000; z-index:2; position:absolute; left:0px; top:0px; width: 100%; height:100%;}
body, label {font-size:100%; font-family:verdana;}
h1, h2 {margin-bottom:0px; }
p {margin-top:0px;}
</style>

<script language="JavaScript">
var content_shield = null;
var modal_dialog = null;

function getPageSize(){
var xScroll, yScroll;
if (window.innerHeight && window.scrollMaxY) {
xScroll = document.body.scrollWidth;
yScroll = window.innerHeight + window.scrollMaxY;
} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
xScroll = document.body.offsetWidth;
yScroll = document.body.offsetHeight;
}
var windowWidth, windowHeight;
if (self.innerHeight) { // all except Explorer
windowWidth = self.innerWidth;
windowHeight = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
} else if (document.body) { // other Explorers
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
}
// for small pages with total height less then height of the viewport
if(yScroll < windowHeight){
pageHeight = windowHeight;
} else {
pageHeight = yScroll;
}
// for small pages with total width less then width of the viewport
if(xScroll < windowWidth){
pageWidth = windowWidth;
} else {
pageWidth = xScroll;
}
arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight)
return arrayPageSize;
}

function launch_file_upload_internal_dialog() {
//In this example, just display some form elements. This could easily be replaced with a call to an iframe
var dialog_html = "<label for='file_input'>Specify a file to upload:</label><input type='file' id='file_input'/><input type='button' value='submit' onclick='hide_modal_dialog()'/>";
dialog_html += "<input type='button' value='close' onclick='hide_modal_dialog()' style='margin-left:30px;'/>";
show_modal_dialog(dialog_html);
}

function body_onscroll() {
window.status = getScrollXY();
}

function show_modal_dialog(dialog_html) {
if (content_shield == null) {
content_shield = document.createElement("div");
content_shield.style.height = getPageSize()[1];
document.body.appendChild(content_shield);
content_shield.className = "content_faded";
window.status="disabled";
//Because the div is only ever going to be the height of the displayable area of the browser (100%),
//it needs to move with the scrollbars (width will always be 100%). We could instead explicitly set
//div height to the complete height of the page including non-visible scrollable areas, but then
//we would need to handle window resize events as well.
//eg. addEvent(document.body, "onscroll", body_onscroll);
}
modal_dialog = document.getElementById("internal_dialog");
modal_dialog.innerHTML = dialog_html;
modal_dialog.style.display = "block";
}
function hide_modal_dialog() {
modal_dialog.style.display = "none";
if (content_shield != null) {
document.body.removeChild(content_shield);
content_shield = null;
}
}

function addEvent(obj, evType, fn, useCapture){
//From http://www.scottandrew.com/weblog/articles/cbs-events
if (obj.addEventListener){
obj.addEventListener(evType, fn, useCapture);
return true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be attached");
}
}

function getScrollXY() {
var scrOfX = 0, scrOfY = 0;
if( typeof( window.pageYOffset ) == 'number' ) {
//Netscape compliant
scrOfY = window.pageYOffset;
scrOfX = window.pageXOffset;
} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
//DOM compliant
scrOfY = document.body.scrollTop;
scrOfX = document.body.scrollLeft;
} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
//IE6 standards compliant mode
scrOfY = document.documentElement.scrollTop;
scrOfX = document.documentElement.scrollLeft;
}
return [ scrOfX, scrOfY ];
}

</script>
</head>

<body>
<div id="internal_dialog"></div>
<input type="button" value="Launch Internal Dialog" onclick="launch_file_upload_internal_dialog()"/>
</body>
</html>