Rails Gotcha: Mocking/Stubbing on an Associated ActiveRecord Object

In RSpec it is still not possible to have mocks or stubs on all instances of a class, although this has been suggested and it is a feature of the Mocha framework. Stubbing or mocking an object returned by an ActiveRecord belongs_to association (i.e. article.author) won’t do what you expect. Instead of mocking the associated object you end up mocking the AssociationProxy object that wraps the associated object. To work around this you can use the AssociationProxy#proxy_target method, something like this:

So when we think we are working directly with an ActiveRecord model, we are in fact working with a proxy object, and this can be confusing:

As far as I can tell this behaviour won’t change with Rails 3 since its AssociationProxy class works the same way.

Rails Tip: Safe Usage of URI.parse

As documented already by Doug URI.parse will thrown an exception if your URL has a trailing space. It also throws an exception on invalid URLs in general. To avoid having URI.parse bomb on your pages you can use a construct like this:

Keep Your I18n Translation Files Tidy

I added the Rake task translate:remove_obsolete_keys that lets you remove all obsolete translations from your YAML files. How is a translation rendered obsolete? Suppose you are translating from english to a number of other languages. Over time you may end up removing a number of I18n keys from the english translation file as your application evolves. The Rake task lets you remove those keys for all locales so you don’t have to do that manually.

Configuring Exception Handling in RSpec and Controller Tests

The ActionController::Rescue module in Rails defines a number of exceptions that will trigger a 404 response, namely ActionController::RoutingError, ActionController::UnknownAction, and ActiveRecord::RecordNotFound. However if you trigger one of those exceptions in a controller test (Test::Unit or Rspec) then rescue and display of the 404 page will not happen and instead the exception will just be propagated. If you prefer checking the 404 response code in your tests over catching one of the exceptions then you can make use of the method ActionController::TestCase#rescue_action_in_public!. The method will set the request.remote_addr to something other than 0.0.0.0 and this will trigger real exception handling. In RSpec you can invoke the method in your spec_helper.rb like this:

One thing to note about this approach is that it means all exceptions will be caught. Sometimes it may be preferable to let the exceptions propagate so that you are able to assert in your tests which exception class should be raised. Even with exception handling activated though, you can still access the exception that was raised by invoking controller.send(:exception) in your tests.

acts_as_bitfield Plugin now Radio Button Compatible

I’ve patched the acts_as_bitfield plugin to recognize “true” as true so that now instead of having to write:

<%= f.radio_button(:email_activated, true, :checked => (”checked” if @item.email_activated?)) %> Yes

<%= f.radio_button(:email_activated, false, :checked => (”checked” unless @item.email_activated?)) %> No

you can omit the checked argument just like with ActiveRecord boolean attributes:

<%= f.radio_button(:email_activated, true) %> Yes

<%= f.radio_button(:email_activated, false) %> No

Rails I18n and 404/500 Error Pages

If you have a multilingual site it makes sense for your 404 and 500 error pages to be multilingual as well. Rails supports multilinguality by serving up error pages with a path like public/500.sv.html, where sv is the locale. In the case where Rails itself is fundamentally broken or fails to respond your webserver will respond with public/500.html, so we need that file as well. A way to achieve this is to keep your 404 and 500 pages as ERB templates with I18n.translate lookups under app/views/errors and have a Rake task that generates the static files under public:

That Rake task can then be invoked by Capistrano in an after_update_code deploy hook to make the pages available in production.

Simplest bit.ly API implementation possible?

To use an URL shortener in your project, I would strongly recommend using bit.ly. It let you set a custom URL (name) and track traffic, clicks and conversations on micro blogs. But best of all, it should be super-fast and super-stable, since Twitter recently chose bit.ly as the shortening service of choice.
Using the bit.ly REST API is also super-easy! Here is how you do it in Rails:
  1. Sign up to get your API username/password here.
  2. Get HTTParty if you don’t already use it: sudo gem install httparty
  3. Copy the code:
    require 'httparty'
    class Bitly
      include HTTParty
      base_uri 'api.bit.ly'
      basic_auth 'username', 'password'
      format :json
      def self.shorten(url)
        response = get('/shorten', :query => required_params.merge(:longUrl => url))
        response['results'][url]['shortUrl']
      end
      def self.required_params
        {:version => "2.0.1"}
      end
    end
  4. Paste code into lib/bitly.rb
  5. Go bananas! Usage: Bitly.shorten(”longurl”)
This is perfect for, as an example Tweeting your URL’s. (I will get back to our Twitter API implementation at Newsdesk.)
The complete bit.ly API docs are here: http://code.google.com/p/bitly-api/wiki/ApiDocumentation
To extend and share this class - use my Gist: http://gist.github.com/112191

We are off to @media, London!

Tomorrow, we are off to @media, London.

Hope to see you there! If you see someone looking like us - don’t hesitate to say hello!

We imagine London to be something like this:

Rails Development Database Setup Without Migrations

I think a lot of Rails developers have been using the db:migrate Rake task to setup new development databases. The problem with this is that over time migrations tend to grow out of sync with the code, especially if you use model classes in your migrations (which in some cases can be very convenient and DRY). A more robust approach to setting up a development database is to load the schema and seed it with data like the db:setup Rake task in Rails 3 does. Now there are a couple of issues for us in using this approach. First we are not on Rails 3 yet (obviously), second we use schema format SQL so the db:schema:load task doesn’t work (see my patch for fixing this), and third, we don’t have a proper db/seed.rb file yet for setting up all the data that so far has been set up by our migrations. To work around these issues I came up with a task like this. The db/development_data.sql file was created by invoking the db:structure:dump task and exchanging the -s option to pg_dump with -a for data only.

Microformats validator/transformator

Today I found an interesting service for Microformats validation/transforming that I found very useful. If you read my previous post about Newsdesk implementing Microformats for contact people you know that my favorite Microformats “tool/validator” so far is the Operator add-on for Firefox.

In a blog post from the Microformats team I read about an interesting service named Optimus that validates and transform your Microformats at a public URI and get the the data back as XML, JSON and JSON-P.

Choose an URI with a contact mark up at Newsdesk:
http://newsdesk.se/pressroom/newsdesk/contact_person/view/peter-ingman-administration-foeretagsledning-14

and just pass it as parameter to Optimus like this:

/?uri=http://newsdesk.se/pressroom/newsdesk/contact_person/view/peter-ingman-administration-foeretagsledning-14

As result you get a nicely formatted XML view with all Microformat information displayed.

<?xml version="1.0" encoding="UTF-8"?>
<microformats from="http://newsdesk.se/pressroom/newsdesk/contact_person/view/peter-ingman-administration-foeretagsledning-14" title="Newsdesk - Peter Ingman (Administration/företagsledning) - Newsdesk">
<description>Peter Ingman är en av grundarna och VD för Newsdesk.</description>
<hcard>
<email>pingman@newsdesk.se</email>
<fn>Peter Ingman</fn>
<org>Newsdesk</org>
<role>VD</role>
<tel>
<type>Work</type>
<value>08 644 89 51</value>
</tel>
</hcard>
<rel-nofollow>
<nofollow href="http://newsdesk.se/search/news">Sök i medier</nofollow>
<nofollow href="http://newsdesk.se/publish">Publicera</nofollow>
</rel-nofollow>
</microformats>

You can also easily get the response data as JSON and define an Callback function with just adding the parameters format=json and function=cbFunction.

/?uri=http://newsdesk.se/pressroom/newsdesk/contact_person/view/peter-ingman-administration-foeretagsledning-14&format=json&function=cbFunction

cbFunction({
"from": "http://newsdesk.se/pressroom/newsdesk/contact_person/view/peter-ingman-administration-foeretagsledning-14",
"title": "Newsdesk - Peter Ingman (Administration/företagsledning) - Newsdesk",
"hcard": {
"email": ["pingman@newsdesk.se"],
"fn": "Peter Ingman",
"org": ["Newsdesk"],
"role": "VD",
"tel": [{
"type": ["Work"],
"value": "08 644 89 51"
}]
},
"rel-nofollow": {
"nofollow": [{
"href": "http://newsdesk.se/search/news",
"value": "Sök i medier"
},
{
"href": "http://newsdesk.se/publish",
"value": "Publicera"
}]
}
});

Microformats Validation

The Optimus service also supports validation of Microformats. Pass your URI that includes Microformats mark-up and add the parameter format=validate and you will get a validator page with information about possible errors.

See Example here (/?format=validate&uri=http://newsdesk.se/pressroom/newsdesk/contact_person/list)