Simple RJS Example

Wasabi Pisum Sativum

Working on a contractual project on the weekend, I spent some time integrating some nifty new technology into a website. The technology was JavaScript, the crusty old web technology which has been crawling around the internet since 1995. Since it's inception JavaScript has played the central role in everything from annoying internet pop-ups to shiny WEB 2.0 sliding divs, and now they've slapped a Remote on the front of it and call it RJS.

I found a plethora of examples on the internet, but nothing that walked me from start to finish through using a RJS template in Rails. I hope that someday the following saves someone else from that void.

Take any old Rails application and add a time controller to it.



# script/generate controller time index
exists  app/controllers/
exists  app/helpers/
create  app/views/time
exists  test/functional/
create  app/controllers/time_controller.rb
create  test/functional/time_controller_test.rb
create  app/helpers/time_helper.rb
create  app/views/time/index.rhtml

The index action will be the one that Rails serves up when you head to the /time url. Modify the app/views/time/index.rhtml to look like:



<%= javascript_include_tag :defaults %>
<div id="current_time"><%= render :partial=>'time/current' %></div>
<%= link_to_remote 'refresh', :url=> {:action=>'now'} %>

Take a second to take that in, because it's the entire meat of the application. We need to include the default JavaScripts because RJS depends heavily on the Prototype library, next we created a div with the id current_time which we will use in our script magic in a second. The last line gives us a link to the now action in the time controller. We don't have that action yet, so open up app/controllers/time_controller.rb and add the new action



class TimeController < ApplicationController
  def index
  end

  def now
  end
end

The controller actions are anything but complicated, but now we need that action to return something. Usually the action looks for app/views/time/now.rhtml but execute and run app/views/time/now.rjs if it does not find it. Don't be silly and try to name your RJS templates the same as some other usable action within your application. Create app/views/time/now.rjs to read



page.replace_html 'current_time', :partial=>'time/current'

This template takes the current page, and replaces the current_time element with whatever is returned from the time/current partial. The partial is rendered from both the RJS template and the index.rhtml template is to ensure the DRYness of our logic. The app/views/time/_current.rhtml template can be as simple as



<%= Time.now().to_s %>

Now if you head to /time on your locally running WEBrick you'll see the current time, but if you mash the 'refresh' all the JavaScript magic replaces the current_time div with your partial. If you examine /time/now you'll see the RJS template is returning a script that is then run by the client's browser. You can start layering on some parameter passing and some data like XML and quickly these RJS templates become very useful in programming some crazy JavaScript, all without writing any actual JavaScript. How very Zen.

Comments (1)

An Example of RSpec

Intense

I've taken a real shining to Behaviour Driven Development since working on my last project. BDD is the next evolution of Test Driven Development, and basically you think about all the behaviours of your system first. Then you write them down (key step here!), and then make your application meet these define behaviours. On a couple of my side projects, I've started using RSpec to implement some BDD.

When I first started out, I noticed a great void of coherent examples on how to use RSpec. Partially because RSpec was changing which broke old tutorials and tests, and partially because the people writing stuff down were so far out on the edge, that what they had didn't help me out in the slightest. I'm throwing this out there, so that you can see how easy it can be to add a specification test to your rails application.

You'll need to have rails, and rspec installed for this to work. Roll out a vanilla rails application and install the rspec plugins:


# rails myapp
# cd myapp
# ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/REL_1_0_0/rspec
# ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/REL_1_0_0/rspec_on_rails

Add the -x flag to the install command if your code is already in subversion so that svn:extern is used and you can pick up RSpec updates. Now, we need to bootstrap rspec, and create the user object we are going to be writing specifications for:


# ruby script/generate rspec
# ruby script/generate rspec_model user

Now that all the monkey work is done, we can get down to business, I quickly modified the db/migrate/001_create_user.rb to read:


class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.column "identity", :string
    end
  end

  def self.down
    drop_table :users
  end
end

Boring, eh? Well I'm trying to keep it that way. These examples can really get out of hand, if you aren't careful. What we have is the simplest user model ever, all it's got is an identity column. Within my application, I would like it to be impossible for a user to exist without an identity. Simple enough, so I modify /spec/models/user_spec.rb to be:


require File.dirname(__FILE__) + '/../spec_helper'

describe User, " in General" do
  before(:each) do
    @users = User.new
    #Identity is a required field
    @users.identity = "http://whatever.com"
  end

  it "should be valid" do
     @users.should be_valid
  end

  it "should be invalid without an identity" do
    @users.identity = nil
    @users.should_not be_valid
  end
end

The first specification is so trivial it appears silly. It is a valid (and it is already in the generated *_spec.rb file) specification, and will blow up if people change what it means for your model to be valid without updating the specification. The rest almost reads itself. You can see we are describing a User, " in General" and that we have two specification, it should be valid, and it should be invalid without and identity. Pretty simple, eh? Well, let's keep it that way. You can now run the specification test:


# rake spec

Uh, oh! FAILURES! Written in red (on colour TTY) is 'User in General should be invalid without an identity' FAILED. Well, of course, we haven't written any code to invalidate a user without a identity; up to this point, we've only been writing specifications. To make our application meet the meager specifications I changed the app/models/user.rb to be:


class User < ActiveRecord::Base
  validates_presence_of :identity, :message => "Identity is required"
end

Now if I run the rake spec again, I can see that my application is up to specification. That's it. Done, Kaput, and still useless. But, at least we have a starting point. The next steps would be to write down more specifications, and then make the application pass those specifications tests. Repeat, until you have an application that meets all your specifications. Some other nifty things that rspec can bring to the table are rake spec:doc which writes out some bullet point specification (Great to give to the pointy haired manager when he comes askin' what specification to which you were building the application. rake spec:rcov will give you a coverage report of your specification tests (in case you cheated and went ahead writing code without specifying it's behaviour). Already my application has a pile of specifications written for it, and it's weird how you just write better code when you stop to think what you really want it to do first.

Comments

An Ugly New Website

Lauren is a Drama Queen

I've been thinking about getting away from Typo for a little while now. It's a decent little engine, and was my first real run with Ruby on Rails, but there was a couple of things that were always under my skin.

After some looking on the net, I found that all the cool kids are using Mephisto for their web logging needs. I grabbed a copy and took it for a spin on my test site, and was quite impressed. I decided I would share with you all how I made the transition, although I think I was the last person using Typo.

The first thing was to make sure I didn't mangle my current, production database so I created a new one through the web panel and then:

mysqldump -u olduser -p oldpassword -h mysql.existinghost.com existing_database \
| mysql -u testuser -p testpassword -h mysql.testhost.com testing_database

I now had a testing_database that I could wreck havoc with. Next I needed the bleeding edge of Typo, so that I could migrate my database to the current version. I couldn't do this with my current version because I wasn't ready to upgrade my production site to the newest Typo. Therefore I:

svn checkout http://svn.typosphere.org/typo/trunk typo_delete
svn checkout http://svn.techno-weenie.net/projects/mephisto/trunk .

Now I had the lastest version of Mephiso installed in my testing webroot, and typo where I could use it. I then updated the database.yml files for both applications so that typo pointed to the testing database, and Mephisto had production set to a brand new database, as well as the typo entry set to the testing database. Once that was done, I started the migration

cd typo_delete
rake db:migrate VERSION=56

You needed to specify the version to stop at, because the bleeding edge of Typo breaks the Mephisto conversion script. Then we are ready to bootstrap the new database, and migrate the data over

cd ../mephisto
rake db:bootstrap
script/runner "Mephisto.convert_from :typo" -e production

At this point I could not log into the admin application with my old Typo user. The problem was that my user appeared to be missing a validation time, so I logged into the database and:

update users set activated_at = now(), admin = 1 where login = 'wdevauld';

Now I was able to get into the admin applet and check out my articles.

The final conversion I made before switching over was to pre-populate all my tags. I believe that tagging is the future of the internet, and quite a few sites I use (Del.icio.us and Flickr are at the top) implement tagging rather well. I don't want to get caught up in sets, categories or sections so from now on it's all Tags all the time. Most of my Typo articles were categorized to some extent, and the conversion pulled them over into sections. I wanted to pre-populate all my tags with my sections (previously my categories) so I dove into the rails production console and

Article.find(:all).collect do |article|
   Tagging.set_on(article, article.sections.collect{|i|i.name}.reject{|i|i=="Home"}.join(', '))
 end

There in three easy lines of code I had all my articles tagged with their section names. It was a shame I had to pull the Home section out, but under mephisto everything is in 'Home' and I didn't need a 'Home' tag with every old article in it. The last bit of meat to get me happy enough to switch production over was to facilitate the old permanent links, so I edited config/environment.rb to include:

Mephisto::Routing.redirect 'articles/*' => '$1'

and I was ready enough to go. The old RSS feed doesn't work anymore, because Mephisto facilitates Atom feeds, and that's the way it's going to be. Those that are tech savvy enough to use a feed reader for my blog, are surely not going to be stumped enabling the Atom feed.

This is the first post under the new regime, and I've been compiling a list of what I still need to do in order to be happy again:

  • Fill the sidebar up again:
    • Recent Del.icio.us tags
    • Monthly archives
    • Flickr stream
    • Blog-roll
    • Perhaps some feedburner love
  • Code formatting
  • Automagic pings to all my favorite sites
  • Way more Style!

I was hoping to participate in the CSS Reboot this spring, but I want to have the new look in place before them. Although with how busy I've been lately, I think May 1 is a reasonable deadline.

Comments

Rails: Easy Multiple Selects

Fish Creek Park

Large version here
Again, the geek content is high in here. If you don't give a rat's ass about web developement frameworks, or don't know what one is, you should just finish this visit with a look at the pretty picture.

First, and foremost, Rails is sweet. If you've ever spent any time dealing with a web development framework, as soon as you dig into Rails you will understand these people know the way that is it supposed to be. I remarked to a co-worker that the reason I like Rails is that the database, if done correctly, is transparent. You only need to deal with the logic of the objects, and their persistant storage is secondary.

Jerry and I have been embarking on a black hat operation to sneak more Rails into our application. Recently, we've been looking at an alarming alert mechanism. Within the workings of this particular application I came across some implementation details regarding Rails that I thought I'd share with those that found me through google, just in case I've delt with this problem before you have.

Implementation details have been changed to protect the innocent.

Let's pretend we need to keep track of rubber duckies and the bathtubs that they are found within. Being that I'm coming from a DBA background I'd like to make the database objects first

create table rubber_duckies (id int not null auto_increment, name char(64), primary key (id));
create table bathtubs (id int not null auto_increment, name char(64), primary key (id));

Rails has an amazing amount of magic to deal with references. We want a rubber ducky to be able to go to multiple bathtubs (You never know when Ernie will visit), and a bathtub should be able to house more than a single ducky. This n-to-m relationship can only be encapsulated in a reference table, so create the table:

create table bathtubs_rubber_duckies (bathtub_id int not null, rubber_ducky_id int not null);

You need to put the references in alpha-numeric order for this work. So because we are dealing with bathtubs and rubber duckies we need to respect that bathtubs are first in alphanumeric order. Of note: You can't put an ID column on a reference table, or Rails will puke.

Now we need to tell the Rails models that we have a relationship between the database objects. So after you've generated the scaffold you can edit app/model/bathtub.rb to read:

class Bathtub < ActiveRecord::Base
        has_and_belongs_to_many :rubber_duckies
end

and app/model/rubber_ducky.rb to be:

class RubberDucky < ActiveRecord::Base
        has_and_belongs_to_many :bathtubs
end

Now that we've established that a ducky can be found in multiple bath tubs and that a bathtub can have multiple duckies, we're finally down to the meat. Most of the hard work is already done because of the strict naming we used in our tables. Firing up the console at this point will show you that a rubber_ducky object will have a collection of bathtubs attached, and vice versa.

From the front end, we want to be able to assign a Rubber Ducky to any number of bathtubs through a multiple select box, so we modify app/views/rubber_duckies/_form.rhtml and add:

<p><b>Bathtubs</b></p>
<% selected = @rubber_ducky.bathtubs.collect {|bt| bt.id.to_i } %>
<select name="rubber_ducky[bathtub_ids][]" size="3", mutliple="multiple">
<%= options_from_collection_for_select Bathtub.find_all, 'id', 'name', selected%>
</select>

The naming of your multiple select with tell rails that the information you are sending back is a list of bathtub identifiers for your ducky that you are editing or creating.

Now, we have support for a multiple select that allows for a subset of a collection to be saved to an object. I've dealt with other frameworks, and with most it's not this nice.

Comments

HDR 101

Northern Sky

As I was heading home this evening, I noticed that the sky was getting some nice colour. I pulled into Nose Hill Park just off 64th, set up my tripod and camera (yes, I did just happen to have it with me).

Sunsets are notoriously hard to meter, but we do get a little leeway using digital. The original, manual, way was to bracket your shot, so that you were sure that you would get at least one that was the correct exposure. Now that same old trick is the cornerstone for the new digital hotness.

High Dynamic Range is a trick that was developed to help deal with the fact that digital cameras can't encapsulate as much of a dynamic range than film. The result is much more detail in your blacks and whites, and some amazing colours.

First you need to get some bracketed shots. Most cameras do this automagically, but if you can't figure it out, you just need to use the manual mode to create a set of shots where one is overexposed, one what you believe to be right, and one overexposed. Be sure to use a tripod, or it's all for naught.

Next, you need to load up Photoshop. Select Tools->Automate->Merge to HDR... Browse for your photos and be sure to check off the automatic align source images. Here you can set the colourdepth per channel. I usually run with 16, because my poor PC hates 32, and 8 bit doesn't really gain you much. Now move the slider until you have a good contrast within your shot, then continue. Next you will get to set your exposure and gamma. I usually play them against each other to get the details where I want them in the photo. If you turn your exposure up, you can pull your gamma down in order to maintain the overall greyness of your photo. Vice versa if you want to bring up the details in your blacks and not blow out the whole picture.

You will now have a beautiful image to continue with your normal Photoshopping.

Comments