Using Rcov to measure the test coverage of Rails plugins

To view the coverage of your plugins using Rcov, first install the rcov gem with sudo gem install rcov, then copy and paste the following onto the end of the Rakefile inside your plugin directory:


require 'rcov/rcovtask'

desc 'Measures test coverage using rcov'
namespace :rcov do
  desc 'Output unit test coverage of plugin.'
  Rcov::RcovTask.new(:unit) do |rcov|
    rcov.pattern    = 'test/unit/**/*_test.rb'
    rcov.output_dir = 'rcov'
    rcov.verbose    = true
  end
  
  desc 'Output functional test coverage of plugin.'
  Rcov::RcovTask.new(:functional) do |rcov|
    rcov.pattern    = 'test/functional/**/*_test.rb'
    rcov.output_dir = 'rcov'
    rcov.verbose    = true
  end
end

You can now simply run rake rcov from inside your plugin directory which will generate an rcov directory with the results. Open rcov/index.html (if you are on OSX this will open automatically) in a browser to view the results.

Thanks to “Mike Clark”:http://clarkware.com/cgi/blosxom for his “Rcov rake task for Rails”:http://clarkware.com/cgi/blosxom/2007/01/05#RcovRakeTask which this task is based on.

*Update (11-11-08):* Changed code to use the RcovTask class.

Autotest Growl Fail/Pass Smilies

John Nunemaker posted a handy tip on “setting up autotest to work with Growl”:http://railstips.org/2007/7/23/autotest-growl-pass-fail-notifications

I use this all the time now however I didn’t like the ugly smilies (call me shallow if you like). I used “Wolfgang Bartelme’s”:http://bartelme.at “Smily Devkit”:http://bartelme.at/journal/archive/smiley_devkit to make a couple of PNG’s slightly more pleasing to the eye.

p=. !http://thelucid.com/files/fail.png(Autotest Fail image)!
!http://thelucid.com/files/pending.png(Autotest Pending image)!
!http://thelucid.com/files/pass.png(Autotest Pass image)!

The zip file can be downloaded here: “autotest_images.zip”:http://thelucid.com/files/autotest_images.zip

*Update* 17-08-07: Added ‘pending’ image for RSpec as requested by Aslak Hellesoy

Rails Edge: Getting your view extensions ready for edge

Following my previous post, below is a modified version of “John Nunemaker’s ‘Renaming RHTML to ERB'”:http://railstips.org/2007/3/4/renaming-rhtml-to-erb to take into account the format in the extension, and handle “the RJS issues I was having”:http://www.thelucid.com/articles/2007/05/16/rails-edge-view-file-extention-functionality-has-changed.

namespace 'views' do
  desc 'Renames all .rhtml views to .html.erb, .rjs to .js.rjs, .rxml to .xml.builder and .haml to .html.haml'
  task 'rename' do
    Dir.glob('app/views/**/[^_]*.rhtml').each do |file|
      puts `svn mv #{file} #{file.gsub(/\.rhtml$/, '.html.erb')}`
    end
    
    Dir.glob('app/views/**/[^_]*.rjs').each do |file|
      puts `svn mv #{file} #{file.gsub(/\.rjs$/, '.js.rjs')}`
    end
    
    Dir.glob('app/views/**/[^_]*.rxml').each do |file|
      puts `svn mv #{file} #{file.gsub(/\.rxml$/, '.xml.builder')}`
    end

    Dir.glob('app/views/**/[^_]*.haml').each do |file|
      puts `svn mv #{file} #{file.gsub(/\.haml$/, '.html.haml')}`
    end
  end
end

h4. Update

Added haml conversion.

Rails Edge: View file extention functionality has changed

It seems that on edge revision 6502 and later, the way that view file extensions has changed considerably.

I couldn’t work out why my tests were breaking when doing an xhr request to a new action which had a respond_to block setup for both html and js. It was returning the html instead of the rjs??

It turns out (after tearing my hair out for over three hours) that “Changeset 6499″:http://dev.rubyonrails.org/changeset/6499 changes things in such a way that the normal new.rjs naming will not get picked up on an xhr request, you now need to add the request format to the extension before the template type i.e. new.js.rjs

This seemed a little odd at first but I am guessing it means you could have a new.js.erb file which is pretty cool as you could achieve the same as “Dan Webb’s MinusR plugin”:http://www.danwebb.net/2006/11/17/rjs-minus-r.

What does seem a little odd is that a new.rjs will get picked up if you don’t give a respond_to at-all (I don’t know if this is a “feature” or a bug).

I’m am hoping that this may save someone some time.

Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X Tiger – The Easy Way

“Dan Benjamin”:http://hivelogic.com/authors/danbenjamin recently updated his very helpful article entitled “”Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X”:http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx”.

I don’t know about anyone else but compiling software is not one of my favourite pastimes. As I’ve been chopping and changing macs lately I thought I’d write a couple of shell scripts to get things right before running anything on my nice new (freshly installed) MacBook Pro.

h3. Prerequisites

There are a couple of prerequisites in addition to what’s on Dan’s “”What’s Needed”:http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx” list before running “the scripts”:http://svn.soniciq.com/public/rails/tools/osx_development_setup/. The first is that you must have MySQL installed as referenced in “Dan’s article”:http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx, and the second being the following:

Ensure you have the following line at the end of your ~/.bash_login file:

export PATH="/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin:$PATH"

You can add this by typing nano ~/.bash_login then copy and paste the above line into the end of the file. Once this is done, hit ctrl-x to exit, answering ‘y’ to “do you want to save changes” prompt.

h3. The scripts

There are two scripts, “01_osx_rails.sh”:http://svn.soniciq.com/public/rails/tools/osx_development_setup/01_osx_rails.sh and “02_osx_image_tools.sh”:http://svn.soniciq.com/public/rails/tools/osx_development_setup/02_osx_image_tools.sh and the following will explain how to use them.

h3. Creating your development environment

The first script will install everything in Dan’s article along with the following gems that I use frequently:
* rails version 1.1.6 for support of older rails apps
* bluecloth
* redcloth
* sqlite3-ruby
* ferret
* ZenTest
* redgreen

Right… here we go:

(please read “the licence”:http://svn.soniciq.com/public/rails/tools/osx_development_setup/MIT-LICENCE before running these scripts as although they have been tested on a clean install of Tiger, I can’t take any responsibility if something breaks)
# Download “01_osx_rails.sh”:http://svn.soniciq.com/public/rails/tools/osx_development_setup/01_osx_rails.sh to your desktop
# If you don’t wish to install all of these gems then open the file in a text editor and comment out the relevant lines with a hash.
# Open a new terminal window and type the following:

cd ~/Desktop
sh 01_osx_rails.sh


# Go make a cup of tea and watch all the pretty text scroll before your eyes.

That’s it, you should now have a fully working development environment.

h3. Image tools

I use a couple of image tools on my system, GD and ImageMagick (with RMagick). If you wish to install these tools and the related libraries, run the following:

(This script hasn’t been tested as much as the previous one so use at your own risk. If anyone has any bug fixes then please post a comment)

cd ~/Desktop
sh 02_osx_image_tools.sh

h3. We’re done

Please let me know if I’ve missed anything obvious.

I hope this helps anyone else out there with Compilaphobia!

Ruby on Rails Exchange, London

Last Friday, a couple of us from “SonicIQ”:http://www.soniciq.com went to the first “RoR eXchange hosted by Skills Matter”:http://www.skillsmatter.com/rorexchange.

It was a great day with some interesting talks from:

* Chad Fowler
* Tom Locke
* Paul Battley
* James Cox
* Damien Tanner
* Ben Griffiths
* Eleanor McHugh

h3. Chad Fowler – Quick and -Dirty- Clean: Well factored Rails

Chad kicked off with a talk on “Quick and -Dirty- Clean: Well factored Rails”. For me it was one of those talks where you think “If only I heard this 6 months ago!”. The reason I say this is that a great deal of what he was talking about, we now implement on a day-to-day basis, but we have gotten there the hard way through making the mistakes that he mentions.

He talks about never using instance variables in views, I love that someone has confirmed this as I find it generally bad practice. For a while now we have been replacing them with helpers giving much more flexibility when the controller logic changes.

One great point that was made, was that SQL should never be used in controllers, not even in :order options. I have to admit, in the past I have done this a lot but the suggestion of custom finders in the model are a much better alternative and it keeps with the whole “Skinny Controller, Fat Model”:http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model idea.

One thing I really must get into the habit of using are association proxies for has_many and such like. Chad showed some great examples of this.

I like one phrase that Chad came up with… “Bare Model Finds” which made me chuckle. What he was getting at was something like an account based site where everything should be found via the given account i.e. @account.projects.find(:all)

as opposed to a “Bare Model Find” of Project.find(:all, :conditions => [‘account_id = ?’, @account.id])

The main points I have taken away from this talk (which I am also going to put in a large poster on the office wall) are the folowing:

* No instance variables in views
* No SQL in controllers
* No more than 4 lines in controller actions

h3. Tom Locke – Experiments with Very Rapid Development in Rails

Tom gave a demo of his “Hobo”:http://hobocentral.net/blog/ project which is very similar to a plugin we use in-house (which also may go open source at some point).

One thing I like about Hobo is the incremental nature of the “dryml” views, meaning that you can override certain elements in a default view bit-by-bit, i.e. if you just want a different header for a certain page you don’t need to create a duplicate of the view and change it, you only need to redefine certain elements of the page.

I completely agree with Tom’s views on generators, although he was slightly more diplomatic than I would have been. I am going to be slightly controversial and say that I really don’t like generators except for creating stub files. What happens if you have an authentication system generator which you have used in 50 projects and you suddenly find a security hole?? …You now have to go back through those 50 projects to fix it! [end generator rant]

h3. Paul Battley – Rerouting Rails

Paul attempted to explain how he believes the rails routing system should be re-written. I could see a lot of merit in what he was saying, however I don’t believe it lent itself very well to this type of presentation.

h3. James Cox – Managing a high performance rails app without tearing your hair out

James gave some great tips on easy ways to increase the overall performance of Rails apps. We are in the process of configuring a new server so these tips came at a good time.

h3. Damien Tanner – Extend your Rails application using Domain Specific Languages

Damien explained a roundtrip his company went on with DLS’s explaining that they are great in certain situations but can be taken too far or overused. In the example he gave, it turned out that the DSL he created was overkill for the business problem he was trying to solve.

h3. Ben Griffiths – Are your tests working for you?

For me, this and Chad’s were the presentations that made the trip to London worth while. I am ashamed to say that until now, I have not gotten into TDD (I’ve been using Rails for over a year and a half). It’s not through lack of trying but with clients constantly on your back to get projects out the door, it’s all to easy to dive straight into coding the application and neglecting the tests.

He started with a comparison between testing and the film Predator. This sounds like a strange comparison however it really helped to illustrate the need for a good set of tests.

My main problem with tests were “what do I test?” and “my fixtures need too much maintenance!”. I breathed a sigh of relief when Ben suggested not using fixtures at all as maintaining a load of fixtures really turned me off testing.

This was a great talk and I could bang on for hours on the benefits of testing with Ben’s techniques and his whole take on modular design but I’ll save that for another post. As a side-note, I have been doing TDD ever since this talk.

h3. Eleanor McHugh – Where’s my SQL? Platform-independent database design using Migrations

Eleanor gave some examples of how migrations could be extended with plugins. A lot of the examples she gave were based on what has been implemented in Hobo. There were some interesting points in the talk although my concentration levels were frayed by this point.

h3. Group Discussion

The main point of discussion was views. I think everyone was in agreement that something needs to change with the way Rails handles it’s views. I personally believe that they should be purposefully limiting so that it is hard to do bad things in the view. I am looking forward to seeing views taken to the next level and believe that there will be some large changes before 2.0 based on the comments during this discussion.

h3. After Party

The guys at “Skills Matter”:http://www.skillsmatter.com put on the first 100 drinks at “Liquid” – a Japanese-themed bar. We had a chance to mingle and discuss a few of the points that we forgot to ask after the talks.

Thanks to all the speakers, all in all a great day out.

Videos of some of the talks are now “available online”:http://skillsmatter.com/menu/479. Also, my colleague “Andy”:http://darkliquid.co.uk has blogged about his take on the day: “Part 1″:http://darkliquid.co.uk/2007/2/10/ruby-on-rails-exchange, “Part 2″:http://darkliquid.co.uk/2007/2/11/ruby-on-rails-exchange-part-2.

Maintaining database column order with migrations

If you’re anything like me, you like to keep database columns in a reasonably logical order. In my case I generally keep primary keys as the first column, then content columns, then special usage columns, then foreign keys e.g.

id
name
description
created_on
updated_on
account_id

Now, say I added a ‘slug’ column with a migration:

def self.up
  add_column "projects", "slug", :string
end

That’s fine, I have my new column but it’s after my foreign keys:

id
name
description
created_on
updated_on
account_id
slug

What’s it doing down there? I want it after the ‘name’ column! …wouldn’t it be nice if you could specify an :after option for add_column.

We can make this possible by monkey patching the add_column method at the top of our migration file (I will make this into a plugin when I get time):

module ActiveRecord
  module ConnectionAdapters # :nodoc:
    module SchemaStatements
      def add_column(table_name, column_name, type, options = {})
        add_column_sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
        after_column = options.delete(:after)
        add_column_options!(add_column_sql, options)
        add_column_sql << " AFTER #{after_column}" if after_column
        execute(add_column_sql)
      end
    end
  end
end

This lets us do the following:

def self.up
  add_column "projects", "slug", :string, :after => 'name'
end

Which gives us:

id
name
slug
description
created_on
updated_on
account_id

Much better… this may seem a little petty, however as your tables get more and more columns it makes things much easier to follow.

Please note: I have only tested this with MySQL

h4. Update: this is now a plugin and can be “downloaded here”:http://svn.soniciq.com/public/rails/plugins/iq_migration_extensions/

CSS and JS directories in Rails

One thing that annoyed me when I first started using Rails at 0.14 was that I was forced to put my .css files in a ‘stylesheets’ directory and my .js files in a ‘javascripts’ directory.

Previous to Rails I would put .css files in a ‘css’ directory and .js files in a ‘js’ directory (call me old fashioned). I use the following code in my application helper to allow me to do this:

module ApplicationHelper
  def javascript_path(source) compute_public_path(source, 'js', 'js') end
  def stylesheet_path(source) compute_public_path(source, 'css', 'css') end
end

Just incase anyone else has the same niggle.

*Update 29-11-08:* for Rails 2.2, see new post.

Disabling plugin code in generators/migrations

I have found on numerous occasions that I need to disable certain plugin functionality if running a generator / rake db:migrate etc.

An easy way to disable certain functionality follows:

def method_that_shouldnt_be_run_in_migrations_or_generators
  # Return if we are using a generator or migrations
  script = File.basename($0)
  return if (script == 'generate') || (script == 'rake' && ARGV[0] =~ /migrate$/)
end

Simply RESTful… “The missing action”

UPDATE 15/03/10: The debate continues…

The ideas in this article came about whilst I was test-driving the Simply RESTful plugin following DHH’s RailsConf keynote on the subject.

The philosophy

The first thing I came across whilst experimenting with Simply RESTful (which is great by the way), was that there is no real way of deleting items with javascript disabled. Since I am currently working on a project that needs to function on a variety of mobile devices, this instantly caused me concern.

I could think of a few ways to hack around this limitation, however I was sure there had to be a better way, hence this article. I wanted to keep the current javascript functionality but in addition have a clean non-javascript fallback.

Consider the following:

CRUD Form (GET request) POST action
(C)reate /products/new create
(R)ead /products/24 n/a
(U)pdate /products/24/edit update
(D)elete - destroy

There are three “state changing” actions in CRUD, they are the ‘create’, ‘update’ and ‘delete’. You will notice from the table above that all three have a POST action1, however only two have GET actions… why is this?

Now, you see that dash in the second column… that’s “the missing action”. There is no good reason why our ‘destroy’ action shouldn’t have a corresponding form action (GET request) also. Let me explain myself…

1 The HTTP actions are PUT, POST and DELETE, however in this implementation (due to the limitations of HTML) they are all technically POST’s.

Putting it into practice

So we give ‘destroy’ it’s missing action which will act as a confirmation of our post… and what shall we call this missing action? …why let’s call it delete.

If we fill in this missing piece in our RESTful Rails puzzle, all becomes clear:

CRUD Form (GET request) POST action
(C)reate /products/new create
(R)ead /products/24 n/a
(U)pdate /products/24/edit update
(D)elete /products/24/delete destroy

Our routes would look something like:

map.resource :product, :member => { :delete => :get }</pre>
In our controller would be:
<pre lang="ruby">def delete
  @product = Product.find(params[:id])
end

def destroy
  Product.find(params[:id]).destroy if request.delete?
  redirect_to product_url
end

Our delete.rhtml would look like this:
<pre><h1>Are you sure you wish to delete ?</h1></pre>

Slight complication…

Update (13 Oct 2007): This has been fixed in more recent versions or Rails.

Now comes the slight complication… we want the javascript POST to /projects/24 to function as normal, however if javascript is disabled we want to request /projects/24;delete.

Wouldn’t it be nice if you could specify a fallback (non-javascript) href in the link_to helper, something that I’ve pondered with on many occasions. Unfortunately the link_to helper doesn’t let you override the href attribute (currently it adds a second one instead), until now.

Enter iq_noscript_friendly plugin which fixes this shortfall (I also have this as a Rails patch however the ticketing system on Trac is currently broken).

Install the plugin using:

./script/plugin install http://svn.soniciq.com/public/rails/plugins/iq_noscript_friendly/

In our listing view (index.rhtml) we are now able to do the following:

link_to 'Delete', product_url(product),
          :confirm => 'Are you sure?',
          :method => 'delete',
          :href => delete_product_url(product)

Ideally you would just give the link a class of “delete” and use unobtrusive javascript to make it do the delete request.

Beautiful.

Summary

By adding “the missing action”, we are able to POST as usual (using javascript) to ‘destroy’ but gracefully fallback to our ‘delete’ form when javascript is not available. Besides, why shouldn’t ‘destroy’ get it’s own form action… ‘create’ has ‘new’ and ‘update’ has ‘edit’?

Now to make this whole thing even better, lets make it part of the convention. ‘delete’ should default to GET and therefore negate the need for :member => { :delete => :get } in our routes.rb… DHH?

I would love to hear peoples comments on this technique as I’m using it for everything now and it works a treat.

Com’on… use “the missing action”, be kind to those without javascript, and lets make it the convention!

Rock on RESTfulness.