Yes, snow can be beautiful. Skyscrapers glisten through unique flakes of frozen crystals as they lay fresh white blankets across the urban landscape. Then, those blankets are mixed with salt and dirt, causing them to melt into a never ending stream of substance that amounts to the dirt, grime, and waste of the millions of people, cars, dogs, even horses that pollute the streets and sidewalks each day. I hate the city when it snows.
-
15 Feb 2006 New York City Snow
-
13 Feb 2006 Lava Lamp Builds
The benefits of an automated build/test/package system are, in my opinion, quite obvious. But sometimes it takes a little bit more than statistical evidence to get you motivated. At my current project, we've been thinking about setting up such a system for some time now, but it wasn't until a colleague of mine stumbled upon the system described in Mike Clark's Pragmatic Project Automation that we realized we could include Lava Lamps and home automation devices to display the status of the current build. Fun stuff!
I'm happy to report that the system has been functional for about a week now, and I don't know how we ever lived without it. The Lava Lamps (or 'Extreme Feedback Devices' as Mike Clark calls them,) are very effective. As soon as someone sees the red light come on, they immediately look to see who made the last change to the code base so they can begin their tormenting. The system truly makes you want to keep your code base clean and your unit tests running without any errors.
If you're thinking of implementing a similar system, here's a list of things you'll need to get things rolling:
- X10 FireCracker home automation kit
- CruiseControl automated build system
- An Ant build script for CruiseControl to invoke
- The X10 Publisher for CruiseControl written by Mike Clark
- Two Lava Lamps to indicate the build status
Extensive documentation is available in the book and on the book's website to fit these pieces together, but a few snags and surprises were discovered along the way that I feel should be documented.
- The Java Communication Library (in its current version of 3,) is not available for Windows. Therefore, if you're forced to work on a windows machine, its up to you to find a copy of the old version 2 Library. I found a copy of it here.
- The X10 devices don't seem to work as advertised through our building's electrical system. We found that the transceiver and the lamp module have to be plugged into the same power strip. This presented a problem for us, as we wanted to have a single transceiver with multiple lamp modules scattered around the cubicle farm. We were able to get around this by using a transceiver and a lamp module at each cubicle. I don't know how far the transmitter will work, but we tested it up to about 12 cubicles away without any problems.
- CruiseControl gives you the ability to automatically send e-mail to certain people whenever the build breaks. We thought this was such a cool feature that we just couldn't wait to throw a bunch of e-mail addresses in there. Be warned that as soon as your manager starts receiving these, he/she will get all kinds of crazy ideas ("Let's integrate this thing with PeopleSoft and include it into our monthly report to the steering committee!")
If I run into some spare time in the near future, I'm gonna see how hard it would be to get this thing running within a Ruby On Rails development environment. If that day ever comes, I'll be sure to post my findings. In the meantime, be sure to hit me up with any suggestions!
-
01 Feb 2006 Live Search With Ruby On Rails
Gone are the days of actually submitting your search query and waiting for an entirely new page to be rendered. The 'Live Search' era is upon us, and I'm here to welcome it with open arms. My first encounter with a Live Search type of form was some time in 2005 when Google launched Google Suggest. I was so blown away that I figured only a giant company full of PhD's could figure out how to implement this. Boy, was I wrong.
I'm here to discuss a step-by-step procedure for adding a live search feature to your Ruby On Rails application, and some of the peculiarities you may encounter while walking through the steps. The wiki on the Rails site is the only real resource I could find regarding live search, and it will be the basis of our discussion here.
Implementation Steps
The steps to adding live search to your Ruby On Rails app are as follows:
-
Include the default Javascript files in your page
<%= javascript_include_tag :defaults %>
OR
<%= define_javascript_functions %>
Both of these will give you access to the ActionPack Javascript libraries. The difference is thatdefine_javascript_functions
will place ALL of the ActionPack Javascript within a<script>
tag on your page, where thejavascript_include_tag
will simply link the external ActionPack Javascript files to your page. (HINT: usejavascript_include_tag
) -
Create a text field for your users to enter their search criteria. We'll use 'search' as our id and name attributes, but feel free to use any value you want.
<input type="text" id="search" name="search" />
-
Create an image to be used as a status indicator while the search is being performed. Be sure to set an id and add an inline style rule to force the image to not show initially.
<img id="busy" src="/images/spinner.gif" style="display:none" />
If you're looking for some images to use on your site, some are available here. Also feel free to use the modified spinner indicator I'm using on this site. -
Create an empty div where you would like the results of the search to be rendered. Be sure to give the div an id.
<div id="searchResults"></div>
-
Create an Ajax observer to observe the text field while the user is typing. The value of the first parameter should be whatever you chose as an id in step 2.
This is where we get a first glimpse of the power inherent in the Ajax helpers. To implement this directly through the XMLHttpRequest object would be much more difficult, error-prone, and messy. Let's take a look at each of the expressions we're using here<%= observe_field 'search', :frequency => 0.5, :update => 'searchResults', :url => { :controller => 'blog', :action=> 'search' }, :with => "'criteria=' + escape(value)", :loading => "document.getElementById('busy').style.display='inline'", :loaded => "document.getElementById('busy').style.display='none'" %>
:frequency
- The frequency, in seconds, that you would like the field to be observed:update
- The id of the element where the search results should be rendered. This is the id you chose in step 4:url
- The controller/action that implements your search functionality (see step 6):with
- Used to pass a parameter called 'criteria' which will be set to the value of the text field at the time of the observation. The call toescape
ensures that any special characters in the input are escaped. Note that we are breaking out of the traditional form-submission process where a request parameter is automatically created for a form element when the form is submitted. We technically don't have a form in this case (more on this later.):loading
- used to display the busy indicator image you created in step 3. The Javascript placed here will be executed when the search results element is being loaded with data:loaded
- used to hide the busy indicator once the search results element is done loading.
-
Create an action in the controller of your choice that will provide the search facility. Let's assume we have a model called 'Blog' with the blog's contents being stored in the 'content' column.
This search function will perform a simple sql like query on the blog's criteria column. Depending on the size of your site and the volume of content you have, this may or may not be a sufficient way to search. For our purposes here, this method works just fine. Once the results have been gathered, we render the search results (using no layout) with the page you will create in the next step. Also note that we have set an instance variable,def search if 0 == @params['criteria'].length @items = nil else @items = Blog.find(:all, :order_by => 'title', :conditions => [ 'LOWER(content) LIKE ?', '%' + @params['criteria'].downcase + '%' ]) @mark_term = @params['criteria'] end render_without_layout end
@mark_term
, that we can use to highlight our search criteria within the rendered search results. -
Create a search.rhtml view page to display the search results.
If<% if @items && @items.length > 0 %> <ul id="searchResults"> <% for blog in @items %> <li> <%= link_to @mark_term ? highlight(blog.title, @mark_term) : h(blog.title), :controller => "blog", :action => "show", :id => blog.id %> </li> <% end %> </ul> <% elsif @mark_term && @mark_term.length > 0 %> No Results <% else %> <% end %>
@items
is not nil or empty, then we display our search results as a list of links to each blog entry's 'show' action, highlighting the given search term within each link. If you would like to change the appearance of the highlighting, simply add a style rule for the class 'highlight' in your style sheet. If the@mark_term
is not nil or 0 characters, then the search must not have returned any results, so we simply display 'No Results'. Otherwise, we show nothing since this would indicate that the search field has been cleared.
- We use an
<input>
tag that isn't wrapped with a<form>
tag. -
I'm not sure if I should be as bothered by this as I am, but it just doesn't feel right to have form elements without a form. Let's take a look at the W3C's definition of form elements:
Form elements are elements that allow the user to enter information (like text fields, textarea fields, drop-down menus, radio buttons, checkboxes, etc.) in a form.
The last part is what gets me: in a form. Form elements allow you to capture data in a form. But we have no form here. I suppose you could argue that wrapping the input tag with a form element will do no harm here and will make the page more semantically correct, however; the action attribute would be left empty (or useless, since we have no submit button,) and that would open up a whole new basket of worries.
It is at this point I realized that Ajax functionality may come at a cost. - Rails provides a
text_field
html helper that seems unusable - There is built in support for generating html form elements, but I find them to be unusable in this case. The html form helpers seem to work only when the form is backed by an actual model object. If I am missing something here, please let me know.
- The
observe_field
kind of just hangs out on the page - I find it to have no semantic meaning or proper place. Perhaps all of the observers should be registered in a single place, but I'm not sure if that makes sense either. I suppose you could argue that the
<script>
or<style>
tag is just as semantically incorrect. In any event, it bothers me. - The search is not persisted in the session
- I'm assuming this can be fixed. Perhaps this will be the topic of a later post.
- No JavaScript For You!
-
I personally feel very strongly against limiting a site's core functionality when the user has Javascript disabled. I can see this issue becoming less and less prominent as more mainstream sites are depending on Javascript for core functionality, however; I still see the need to support browsers sans Javascript (Certainly in the case of search functionality.)
If Javascript is disabled in our example here, the user has no way of knowing how to search. They'll enter some text, hit enter, wait, and then get frustrated and leave. Therefore, a button should be displayed for the user when Javascript is disabled (or when the XMLHttpRequest object is not available on the user's browser.) At first glance this problem does not seem to be trivial. There are many factors to consider here (one being the previously stated absence of a form tag and submit button.) This will be the topic of a later post.
- Browser Support
-
I tested this code on all of the browsers I had laying around. I realize this is in no way an exhaustive list, but I found the following browsers to be supported:
- Safari 2.0
- Firefox 1.5 Mac
- Firefox 1.0.4 Linux
- Firefox 1.0.4 Windows
- Mozilla 1.7.8 Linux
- Konqueror 3.5
- Epiphany 1.6.0
- Opera 8.51 Mac
- IE 5.5 Windows
- IE 6 Windows
- IE 5.2.3 Mac
- Opera 7.5.4 Mac
Update - 5/1/2006: I've added another followup here.
-
Include the default Javascript files in your page