Duplo

Building Blocks & Learning Experiences

Browsing Posts in Ruby

I was having some trouble running rspec within Emacs. One of the gems in my Gemfile was pointing to a git repo, and as a result, bundle was shelling out through Emacs to check my revision using this method:

def revision_from_git
  if File.exists?(scope('.git/HEAD'))
   Dir.chdir scope(".") do
     `git rev-parse HEAD`
    end
  end
end

Since my git lives in a non-standard location, it was failing:

/Users/xxxxxxxx/.rvm/gems/ruby-1.9.2-p290@global/bundler/gems/compass-91a748a91636/lib/compass/version.rb:48:in ``': No such file or directory - git rev-parse HEAD (Errno::ENOENT)

Searching for a solution, I found a page in the EmacsWiki that dealt with this issue, but I didn’t care for any of the solutions there. What I went with was to open ~/.MacOSX/environment.plist with the Property List Editor, and add the path to my git executable to the PATH variable therein. I then had to reboot. The reboot seems to be the only way to get launchd to re-read this file. I launch Emacs via Spotlight, and so it is started by launchd behind the scenes. I tried using launchctl setenv first, as mentioned in the EmacsWiki, but that didn’t seem to work, I’m not sure why.

With the PATH variable set, rspec-mode, and rvm.el loaded, I was able to successfully run my specs from within Emacs.

If you happen to have a <select> tag with its multiple attribute set, you can unselect them in Cucumber by adding this step:

When /^(?:|I )unselect "([^"]*)" from "([^"]*)"$/ do |value, field|
  unselect(value, :from => field)
end

The uservoice gem provides a nice easy way to integrate your Rails app with the UserVoice user feedback service. If you’re using Heroku to deploy your Rails app, there are two things that will provide speed bumps. The first is that, short of storing your UserVoice API key in your git repository, there’s no way to get it into your Rails app’s configuration. The second is that the uservoice gem lists rails as a dependency. Both can be overcome, and I’ll describe how.

Securely Passing Your UserVoice API Key To Heroku

In order to pass your UserVoice API key to Heroku without committing it in plain-text in your git repository we make use of Heroku’s config feature.

$ heroku config:add USERVOICE_API_KEY=<your api key> USERVOICE_USER=<your username>

This will make your UserVoice API Key and username accessible to your Heroku Rails app via ENV["USERVOICE_API_KEY"] and ENV["USERVOICE_USER"] respectively.

Now we simply need to get these values into the uservoice gem’s config/uservoice.yml configuration file. To do this, we need to add ERB support to the uservoice gem’s config loadermy pull request has been accepted, and this functionality is baked in to the uservoice gem as of version 0.3.1.

Now we can setup our uservoice gem configuration file like so:

uservoice_options:
  # required
  key: <%= ENV["USERVOICE_USER"] %>
  host: my_app.uservoice.com
  forum: my_app
  # optional
  showTab: true
  alignment: left
  background_color: "#f00"
  text_color: white
  hover_color: "#06C"
  lang: en

uservoice_api:
  api_key: <%= ENV["USERVOICE_API_KEY"] %>

Installing The Uservoice Gem To Heroku

Of course we need to add the uservoice gem to our .gems file. However, the uservoice gem lists Rails as a dependency. This means that when Heroku installs the uservoice gem, it will also install the latest version of Rails (2.3.8 at the time of writing). Heroku’s stack currently relies on Rails version 2.3.5, and having the two versions of Rails installed causes a clash. The solution is to add the --ignore-dependencies flag to the uservoice line of the .gems file. However, this means that Heroku won’t install uservoice’s other dependency, the ezcrypto gem. To work around that, we simply add ezcrypto manually, on it’s own line, to the .gems file. The lines that need to be added should look like this:

# <RAILS_ROOT>/.gems
ezcrypto --version '>= 0.7.2'
uservoice --version '>= 0.3.1'  --ignore-dependencies


While the version arguments aren’t strictly necessary, I’ve found it helpful to be explicit when specifying gems, to help alleviate issues caused by new versions of gems being released in the middle of my development cycle.

With those changes in place, you should be able to push your git repository to Heroku and receive all sorts of great user feedback.

This post is a reminder to myself, that when I upgrade my webrat gem, I need to replace its vendor/selenium-server.jar. If I forget, then Selenium Remote Control will most likely break because the version of selenium-server.jar included with webrat is old, and doesn’t support current versions of Firefox.

I’ve often been sad that there is no default keybinding for comment-region in Emacs’s ruby-mode. Eventually it annoyed me enough that I added one:

(add-hook 'ruby-mode-hook
	  (lambda ()
	    (define-key ruby-mode-map "\C-c#" 'comment-or-uncomment-region)
	    )
	  )

This assigns C-c # to comment the current region, or if the current region is already commented, it will uncomment the region.

But what about when there’s no region currently marked? It would be nice if emacs would (un)comment the current line. To do this, I took a page from DJCB at Emacs-fu.

(defadvice comment-or-uncomment-region (before slick-comment activate compile)
  "When called interactively with no active region, comment a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (list (line-beginning-position)
	   (line-beginning-position 2)))))

Now with nothing marked, pressing C-c # will cause emacs to toggle commenting on the current line.

In case it isn’t obvious, one should add the abbove snippets to their .emacs file to gain their benefits.

Autotest-inotify is a gem that extends autotest to use Linux’s inotify to monitor changes to your source and test files, running the appropriate tests as files are modified.

By default, autotest implements filesystem polling to detect these changes. This can use a significant amount of CPU cycles1, and can impact battery life in laptops.

Through Linux’s inotify, autotest-inotify inserts callbacks into the underlying filesystem, which allows the filesystem to notify us when files we’re interested in have been modified. This allows autotest to sleep until inotify indicates a change has been made to one our files of interest, i.e. we don’t have to constantly poll the filesystem.

This work was inspired by Sven Schwyn’s work on autotest-fsevent, which extends autotest to use Mac OS X’s FSEvents system, as well as Alban Peignier’s work using the INotify gem. Where autotest-inotify differs from Schwyn’s work, is that autotest-inotify can be used in Linux, whereas autotest-fsevent uses FSEvent, which is Mac OS X specific. Autotest-inotify differs from Peignier’s work in that it offers a simpler gem-based installation, and it is less obtrusive to autotest’s methods for determining which files to watch for changes.

Source code for the autotest-inotify gem can be found at http://github.com/ewollesen/autotest-inotify. It is licensed under the MIT license. See the README for installation instructions.

  1. On one of my machines, ~25% of a single core’s cycles were spent polling the filesystem []

In the process of setting up metric_fu, I found that, one way or another, saikuro’s output wasn’t getting into the correct place. I’ll spare you the long story, and just show the config settings I had to put into my Rakefile to get things working:

config.saikuro = {
  :output_directory => "#{ENV["CC_BUILD_ARTIFACTS"]}/scratch/saikuro", 
  :input_directory => ["app\" --input_directory \"lib"],
  :cyclo => "",
  :filter_cyclo => "0",
  :warn_cyclo => "5",
  :error_cyclo => "7",
  :formater => "text", #this needs to be set to "text"
}
config.flay = {
  :dirs_to_flay => ['app', 'lib',],
  :minimum_score => 10, 
}


My changes in bold.

There are a number of different ways to handle custom error pages in rails. Most use rails’s rescue_from method. This approach allows your error pages to be dynamically rendered in response to errors.

The way I see it, if my site has just encountered an error, I want to immediately go into damage control mode. Do I want to risk dynamically generating an error page? No, not at all. There could be an error in the page rendering that will cause another error when I try to render the error page. Not an ideal situation to say the least. It’s much safer to serve up previously generated static content.

While rails does come with a default, static, error page, said page is largely unstyled, and contains no links to help the user get back to what they were doing. I feel that it’s bad enough that I have to display an error to the user; leaving them with nowhere to go, looking at a jarring, or even ugly, error page isn’t going to make them the happy users that we all want.

Lastly, I don’t want to have to remember to keep the site’s error pages up to date with the latest layout and style.

To summarize, I want static error pages, rendered using rails’s ActionView, and I want them updated automatically any time the site’s style or layout changes.

To accomplish these goals I wrote a rake task and a capistrano recipe. The rake task visits the site, collects the rendered error pages, and stores them in the <RAILS_ROOT>/public directory, where rails will automatically look for them when errors occur. Here’s the rake task:

desc "Generate static error pages (404 and 500)"
task :generate_static_error_pages => [:environment] do
  require "console_app"

  urls_and_paths.each do |url, path|
    r = app.get(url)
    if 200 == r
      File.open(Rails.public_path + path, "w") do |f|
        f.write(app.instance_variable_get(:@body))
      end
    else
      $stderr.puts "Error generating static file #{path} #{r.inspect}"
    end
  end
end

def urls_and_paths
  [["/static/404_not_found", "/404.html"],
   ["/static/500_internal_server_error", "/500.html"],]
end

The capistrano recipe simply runs the rake task each time the application is deployed. Here’s the recipe:

desc "Generate static error pages"
task :generate_static_error_pages, :except => {:no_release => true} do
  run "cd #{current_path} ;
       RAILS_ENV=production rake generate_static_error_pages"
end


I’ve instructed capistrano to execute this recipe each time I deploy my application by using one of capistrano’s many handy callbacks:

after "deploy:symlink", "generate_static_error_pages"

The result is that I have consistently styled, static error pages, that are updated automatically each time I deploy my application.

Voyeur is a very small bit of ruby code that I’ve written to display updates to your MPD stream via Growl.

You can find it here:  http://kill-0.com/voyeur/

You start and stop it as you would a daemon, ie $ ./voyeur start and ./voyeur stop. As an added bonus, you can send it a HUP signal, and it will immediately display the current track information or status. Here’s a screen shot:

Voyeur: Screenshot

I was having all sorts of problems upgrading Mildred to Rails 2.1.  A lot of the errors I was seeing were like the following:

ArgumentError in 'TracksController downloading a track by admin should not be a redirection'
wrong number of arguments (0 for 1)
/Users/ewollesen/src/mildred/app/models/track.rb:52:in `title'
/Users/ewollesen/src/mildred/app/models/track.rb:52:in `filename'
/Users/ewollesen/src/mildred/app/controllers/tracks_controller.rb:49:in `download'
./spec/controllers/tracks_controller_spec.rb:82:

It took me a good while to figure out what was going on. The error was strange because as far as I knew, title was a database attribute in the Album model, which was a descendant of ActiveRecord. There shouldn’t have been any arguments required. Indeed, firing up my debugger and running track.album.read_attribute(:title) returned the expected result of “Test Album 1″. I was very puzzled.

I realized that my title method was being overridden, but by what? I started feeding the title method random arguments in the hopes of learning something new. It wasn’t long before I got lucky:

(rdb:1) e track.album.title("x")
NoMethodError Exception: undefined method `content_tag' for #<Album:0x3d5bbfc>

That tipped me off as to what was overriding my title method. The content_for is part of a pattern I use to set a view’s title in the layout via a method called title in my ApplicationHelper. This made me think of how in Rspec 1.1.4, a Helper module is no longer included by default. I popped over to my application_helper_spec.rb and found something similar to this:

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

include ApplicationHelper

describe "ApplicationHelper" do

This needed to be changed to:

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

describe "ApplicationHelper" do

  include ApplicationHelper

Then all was well. Whew. Just to be sure I didn’t run into this sort of thing again, I went ahead and made sure that all of my other Helper specs followed this paradigm.

This is the second time I’ve run into an issue where RSpec had overridden some seemingly random method in some seemingly random object. I guess there’s a lot of magic in there that I don’t have my head wrapped around yet. I just wish it were easier to spot!