Scott Barron - Ruby on Rails Podcast

Posted over 7 years back at Ruby on Rails Podcast

The founder of the Rails Podcast muses about acts_as_state_machine, running a business, and keeping up your Rails face.

Install your favorite rails plugins easily with Rails Plugin Packs™

Posted over 7 years back at Luke Redpath - Home

After a brief brainwave on the way home from work, I came up with a simple solution to the problem, which I now present to you simply as: Rails Plugin Packsâ„¢.

The concept is incredibly simple; you write your own plugin pack - nothing more than a simple specification written in YAML - and publish it somewhere, either storing it somewhere on your harddrive, on your network or hosted on your website. You then use a series of simple Rake tasks to install/uninstall these packs by simply specifying the URL/path to the pack file.

I've initially implemented this as a Rails plugin, so install it to get going:

$ ./script/plugin install http://opensource.agileevolved.com/svn/root/rails_plugin_pack

This will give you three new Rake tasks - pluginpack:install, pluginpack:uninstall and pluginpack:about. What they do should be pretty self-explanatory. They all take a pack url/path as an argument, in the form PACK=url_or_path, for example:

$ rake pluginpack:install PACK=http://www.lukeredpath.co.uk/mygreatpack.pluginpack

Currently, Subversion is required to use the plugin as it installs each plugin by doing an svn co of each plugin. I plan to expand on the ways of installing the plugins soon, including support for svn export and svn:externals.

Writing your own pluginpacks is simple - the file extension can be whatever you like although I prefer to use the standard .pluginpack suffix. The files themselves are very simple and are written in YAML. Here's an example plugin pack file (which comes bundled with the rails_plugin_pack plugin itself):

about:
  name: Example Pack
  description: An example plugin pack
  author: Luke Redpath
  email: contact@lukeredpath.co.uk
  website: http://www.lukeredpath.co.uk
plugins:
  unobtrusive_javascript: http://opensource.agileevolved.com/..[truncated]
  navigation_mappings: http://opensource.agileevolved.com/..[truncated]

All of the meta-data is optional, although if you omit a name it will result in your plugin being called "Untitled Plugin" so I recommend giving every one of your packs a name, at least.

So what possible uses could this have? I've already discussed facilitating the installation of the same group of plugins on each new project - you could have your own personal or company-wide "standard" plugin pack that you use on each new project. You could write a blog post about your favorite Rails plugins and offer a plugin pack containing each plugin discussed in your article. You could use it to group related plugins. You could even use it as a basic dependency mechanism, by offering packs of plugins that depend on each other (although this is no substitute for a proper dependency mechanism).

The only downside to this at the moment of course, is that Rails Plugin Packs is implemented as a Rails plugin itself, meaning you still need to install at least one plugin manually before you can do anything else on a new project. This isn't ideal and I'm waiting to hear back from Geoffrey Grosenbach about the possibility of submitting a patch to RaPT and rolling plugin-pack functionality into the RaPT core.

Comments are open so as usual, all feedback welcome and appreciated; please file any bugs/issues in the Agile Evolved Trac.

Update: I've made a small change to the plugin pack format so if you've already checked out the plugin you'll need to run an update. I've updated the example above and you can view the actual changes with the trac changeset viewer.

Using Ruby hashes as keyword arguments, with easy defaults

Posted over 7 years back at Luke Redpath - Home

Similar to many Rails helpers/methods, a lot of the methods I write often use an optional hash of options, or sometimes just a hash only, to simulate keyword arguments (often using symbols).

The only downside to doing this is you lose out on easily setting default values using Ruby's default method argument values. You might use code something similar to the following to make up for this:

def some_method(opts={})
  my_foo =  opts[:foo] || 'mydefaultfoo'
end

However, as you have more and more keyword options, setting defaults in this way gets rather tedious. Fortunately, Ruby's Hash#merge comes to our rescue (almost) - it allows you to merge the contents of one hash with another. The only problem - any duplicate keys in the hash you are merging will overwrite your original hash values - when it comes to setting default values, we want this to work the other way around; we only want values in the defaults hash to be merged if they do not exist in the original hash. Again, Ruby comes to our rescue - Hash#merge takes a block as an argument and will pass any duplicate values that crop up into the block - we can use this block to decide which value to keep.

Using the simple monkey patch to the Hash class below, you will no longer have to set each default individually:

class Hash
  def with_defaults(defaults)
    self.merge(defaults) { |key, old, new| old.nil? ? new : old } 
  end

  def with_defaults!(defaults)
    self.merge!(defaults) { |key, old, new| old.nil? ? new : old }
  end
end

Of course, sticking with Ruby naming conventions, with_defaults() will return a new hash whilst with_defaults!() will change the original hash directly. Now all you have to do is something like this:

def my_funky_method(opts={})
  opts.with_defaults! {
    :arg_one => 'foo',
    :arg_two => 'bar',
    :arg_three => 'baz'
  }
end

Update: Dan Web just informed me of another way of doing this - instead of merging your defaults into your options, simply merge your options into your defaults et voila!

def my_method(opts={})
  {:arg_one => 'foo', :arg_two => 'two'}.merge!(opts)
end

If there is one thing that is annoying about Ruby, it's that just when you think you've come up with a cool little code snippet, somebody inevitably comes up with an even easier way of doing the same thing.

That said, I do still think there is something nice about the with_defaults() method - it's slightly more intention-revealing. Weigh that up with the need to monkey-patch. Choose what works best for you.

Update 2: Josh Susser now informs me (see comments) that this functionality is built-right into Rails courtesy of ReverseMerge. I still think with_defaults sounds better but I guess that pretty much makes this post redundant!

We're hiring: Rails developers needed

Posted over 7 years back at Luke Redpath - Home

Things are getting busy here at Agile Evolved and we are looking for UK-based RubyOnRails developers to join our team.

We'e looking at two junior-level development positions. You don’t necessarily need to have RubyOnRails experience but if you do not you will need to be a fast learner and have excellent skills in another language.

You must fulfill the following requirements:

  • Should be able to learn very very quickly.
  • Should have excellent OO knowledge (be prepared to be tested on this).
  • Experience with a scripting language such as either Ruby (preferred), Python, PHP 5 or similar.
  • You must already have the the relevant UK work permits or be an EU resident.
  • Good knowledge of HTML/XHTML and CSS.
  • Basic knowledge of Javascript (You’ll be an expert by the time we'e through with you).
  • You must like or at least smile when using a Mac.

In addition, we'e also looking for a full-time Web Designer. Skills for this position are:

  • Excellent HTML/XHTML and CSS skills.
  • Good design skills.
  • Knowledge of Photoshop and Illustrator.
  • Good Javascript skills.

Of course if you'e one of those few people that can code and do design as well we’d love to hear from you too.

Salaries for these positions are in the £18k to £25k range. Please send your CV/Resume as a PDF (preferred), MS Word or text file to enquiries@agileevolved.com. Please also include a cover letter. No agencies please.

Adrian Holovaty - Ruby on Rails Podcast

Posted almost 8 years back at Ruby on Rails Podcast

The lead developer of the Django framework shares his perspectives on solving the problems of website development.

Testing your Rails views with Hpricot

Posted almost 8 years back at Luke Redpath - Home

Update: This extension is now available as a Rails plugin. See below for more details.

_why released his great little Hpricot HTML parser the other day and the first thing that struck me would be that it would be a great tool for testing the output of Rails views. Rails comes with the built-in assert_tag method but I've always found it clunky and a pain in the arse to use.

By combining the Hpricot library and a few useful helper functions, you can now test the output of your Rails views in Test::Unit::TestCase easily using Hpricot's support for CSS selector searches.

First of all, install Hpricot if you don't have it already:

$ gem install hpricot --source code.whytheluckystiff.net

Next, download the Hpricot Test Extensions file and copy it to the lib folder of your Rails app.

Finally, require the file at the top of your test_helper.rb file:

# test_helper.rb
require 'hpricot_test_extension'

Alternatively, you can also install as a Rails plugin. The plugin is located in the Agile Evolved Open Source repository.

And thats it. You'll now have access to four new methods - tag, tags, element and elements. All four methods take a CSS selector as an argument. The pluralised methods return an array of search results for the CSS query, the singular methods just return the first (handy if you know you'll only have one of a particular element, say, "title"). The tag methods return the inner contents of the returned elements, whereas the element methods return the raw Hpricot::Elem objects for you to work with. Here's a few examples:

assert_equal "My Funky Website", tag('title')
assert_equal 20, tags('div.boxout').size
assert_equal 'visible', element('div#site_container').attributes['class']

Finally, there is a small extension to the Hpricot::Elem object itself which lets you assert the presence of text within an element using an alternative syntax:

assert element('body').should_contain('My Funky Website')

I plan to integrate these helpers into rSpec as well using a more rSpec-style syntax. Any comments and suggestions are welcome.

Annoying IE bug with the script.aculo.us in-place editor

Posted almost 8 years back at Luke Redpath - Home

I came across a rather annoying bug with the script.aculo.us effects library the other day. If you use pass in a loadTextUrl parameter to make the inline editor grab the value from the server, Internet Explorer would throw up the error 'Can't move focus to the control because it's invisible not enabled or of a type that does not accept focus.'.

After digging around in the inplace-editor code, it seems that it was disabling the inplace form field while it sent off an AJAX request to the server to grab the value, then re-enabling it once it the data was returned. The problem seemed to be down to the difference in the way IE and other browsers place focus on the field once it was inserted. Safari and Firefox were both placing focus on the field before it was disabled, whilst IE was trying to focus it after it had been disabled. This is what was causing IE to barf.

The solution? Instead of simply calling the function that retrieves the remote text from the server (which does both the disabling/reenabling and AJAX request) directly, attach it to the field's onfocus event handler. This ensures that it will always get executed after the field has focus.

I've submitted a patch for this which fixes this problem which will hopefully be accepted, so if you've ever had problems with this in IE, this should help you out.

RubySlim - Ruby API for SlimServer

Posted almost 8 years back at Luke Redpath - Home

Just a small announcement for any other Squeezebox/Soundbridge owners out there who use the SlimServer music server. I've started work on a Ruby API for it and you can view the latest source on the Agile Evolved Open Source Trac.

You can also check out the latest source code from Subversion.

Here's a small code example:

slimserver = RubySlim::SlimServer.open('localhost')
slimserver.connect('myusername', 'mypassword')
puts slimserver.version

squeezebox = slimserver.players.first
squeezebox.turn_on
squeezebox.current_playlist.play

And in the future...a full RubyOnRails, AJAX-enabled front-end to the SlimServer for browsing your music collection, creating playlists, controlling your SqueezeBox and more. I've not checked anything in on this but I've already been experimenting with creating ActiveRecord models that interact with the SlimServer database. You could do something like this (this is actual code that I have got working):

my_favorite_album = Album.find_by_title('The Number Of The Beast')
squeezebox.current_playlist.load :album => my_favorite_album.id

Finally, if you have access to the SlimServer CLI API (click on technical information on your SlimServer web interface menu) you can play with any parts of the CLI API that I'm yet to add to the Ruby API by using the raw connection and API object:

# make sure you are using the CLI port, not the web interface port
connection = RubySlim::SlimServer.raw_connection('localhost', 9090)
slimapi = RubySlim::SlimAPI.new(connection)

# invoke any api commands
slimapi.invoke("version")
slimapi.invoke("myplayerid player status")

For those interested in the concept of behaviour-driven development, the whole thing is specced using rSpec. Admittedly its not the greatest exercise in BDD because I'm simply wrapping an existing API in a Ruby API so there wasn't more than 1 context for most classes, but it was still great to use and the built-in mock objects API -- which seems very similar to FlexMock -- was very easy to get to grips with - great for mocking out those telnet connections to the SlimServer CLI.

Update: RubySlim is now hosted as a RubyForge project. The 0.1 release is available as a gem.

$ gem install rubyslim

Moving from Eyelook to Smugmug

Posted almost 8 years back at

I needed to host photos from a recent trip to New Zealand. I started modifying eyelook to make it easier to do what I wanted such as geocoding, bulk upload, hierarchial grouping, different sizes, different layouts, themes etc. It was taking a bit of time so I decided to look around at existing services but none of them suited my needs.

Then I found SmugMug and I was hooked. This is the best photo-sharing service I have seen. It seems to be aimed at professional photographers – there is no free version but you get what you pay for. It is far from perfect but there is no way I would consider anything else at this stage.

Luckily it has a referral system that gets you $5 off your first year if you indicate an account that got you onto the system so I got mine a little cheaper. I also helped out the friend that referred me by making it a little cheaper for them next year. If anyone wants to get same deal, it’s simple: enter my email address ( peter at realityforge dot org ) or my coupon ( EqCTz7hz7wkW2 ) in the ‘Referred by’ field on the signup form and you get $5 off.

Best photo sharing service yet!

RailsConf 2006: Marcel Molina and Sam Stephenson - Ruby on Rails Podcast

Posted almost 8 years back at Ruby on Rails Podcast

Hear about integration tests, optimization, and the tumblelog from Sam Stephenson (creator of Prototype, Rails core, 37signals) and Marcel Molina (Rails core, 37signals).

RailsConf2006 Aftermath

Posted almost 8 years back at RailsExpress.blog

As promised during my talk at RailsConf, I have uploaded a new version of my railsbench package to rubyforge. You can either download the tar ball or get the new version using svn. Apologies to all users which have a checked out and modified version of the old CVS archive. I decided to convert from CVS to subversion since I kept typing svn commands at my CVS archive, so it had to go.

The svn url for railsbench is svn://rubyforge.org//var/svn/railsbench/trunk/railsbench

The new version now supports running ruby-prof as an alternative to SVL's Ruby Performance Validator. This should make some Mac and Linux users happy. However, ruby-prof is only a weak substitute for a good profiler.

Profiling with ruby-prof requires ruby 1.8.4 and works like this:

perf_prof n "-bm=benchmark_name other_options" config_name

This will run the named benchmark n times using ruby-prof and store the resulting HTML formatted profiler graph into $RAILS_PERF_DATA

Happy profiling!

PS: My presentation given at RailsConf2006 is available for download.

Updating a single record attribute with ActiveRecord

Posted almost 8 years back at Luke Redpath - Home

On a Rails project I'm working on at the moment, the Rails app had to make calls to a third-party application using web services - we would then update certain attributes on a particular model instance with data returned by the web service. The only problem was that the third-party app had to update (different) attributes on the same record. Whilst the web service would always respond in a timely fashion, there was no way of predicting when the third-party app would run its update (it could be delayed if the server the server was under heavy load).

This resulted in a race condition that could potentially result in a loss of data. Because Rails already had a loaded instance of the object in memory before the web service call was made, if the third-party app saved its changes before Rails saved the record with its own changes, the values already loaded in the Rails object would overwrite the new values written by the third-party ap

The solution seemed obvious at first - instead of doing:

obj.some_attribute = 'foo'
obj.save

We could simply do:

obj.update_attribute('some_attribute', 'foo')

But we were mistaken. Whilst the method's name would seem to imply that ONLY a single attribute would be updated, this is in fact not the case. All update_attribute() does is exactly the same thing as the first code snippet. From the Rails source:

def update_attribute(name, value)
  send(name.to_s + '=', value)
  save
end

As it turns out, there isn't a built-in way of updating just a single attribute that we could see. So we wrote our own, simple solution:

def update_single_attribute(attribute, value)
  connection.update(
    "UPDATE #{self.class.table_name} " +
    "SET #{attribute.to_s} = #{quote(value)} " +
    "WHERE #{self.class.primary_key} = #{quote(id)}",
    "#{self.class.name} Attribute Update"
  )
end

Feel free to use this in your own apps if needed - the easiest way to use is it is as a monkey patch to ActiveRecord - simply paste the following code into a file called active_record_patches.rb in your app's lib folder and require it at the bottom of your environment.rb file. Alternatively, you could patch the Rails source directly or convert this to a Rails plugin.

Josh Susser - Ruby on Rails Podcast

Posted almost 8 years back at Ruby on Rails Podcast

Newly knighted Rails blogger Josh Susser muses on database relationships and reliable apps.

Common Rails Performance Problems

Posted almost 8 years back at RailsExpress.blog

InfoQ has published an article on common Rails performance problems (written by me). You can head over to read all about it.

David Black - Ruby on Rails Podcast

Posted almost 8 years back at Ruby on Rails Podcast

The RubyCentral co-founder talks about his new book, Ruby for Rails.