Archive for 'Ruby on Rails'

Rails handles exceptions that occur in production mode by rendering the file public/500.html or one of the other two (404.html and 422.html) if appropriate. Generally this is a good default, but in some cases it is a requirement to redirect the user to, or render specific pages for different types of exceptions. For instance, when an application provides a JSON API, it would be bad to return a 500.html to the caller when something goes wrong.

There are generally two ways do this in Rails. Either overwrite rescue_action_in_public in your controller or use the newer rescue_from to map exceptions to a handler. Ryan Daigle wrote a short but comprehensive blog post on this topic.

However, testing this is a bit tricky. config.consider_all_requests_local needs to be set to false and local_request? should be set to false as well. Testing this manually in the browser is cumbersome and error prone, so I needed a way to verify the behavior with a controller test. A quick ack –ruby rescue_action_in_public actionpack-2.3.4 turned up /actionpack-2.3.4/test/controller/rescue_test.rb exactly what I needed.

As it turns out, this is actually quiet easy to test. Basically, there are four things to consider and you are good to go:

1. Simulate the production environment in a setup method

2. Create a dummy controller with actions that reproduce the errors you want to test

3. Generate a route for your dummy controller if you have deleted the default routes in routes.rb

4. Call those methods in your test cases

With these four steps we got most uses cases covered. I ran into a problem, where I wanted to test an error that occurred during template rendering and required some special exception handling code. This is what worked for me:

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Two weeks ago I stumbled upon a weird globalize2 behavior in a Ruby on Rails application I was working on.

globalize2 creates a has many association on a translated model that points to a proxy class. This proxy class holds the model translation for any given language. So if I tell it to translate a model called Tag, it will create a class called TagTranslation on the fly.

I needed to add behavior to TagTranslation. I wanted to add a before save hook that makes transformations on an attribute before it gets saved. Therefore, I created an active record model called TagTranslation and added the hook. This worked wonderfully in test environment but not in the development environment. For some reason, the transformations weren’t made.

A short debugging session in script/console revealed that there was no before save hook on TagTranslation in development mode. More precisely, the class never got loaded. So I dug into the globalize2 code and found out that it just overrides an existing class with the same name.

So what happened? In that particular case, this happened when config.cache_classes was set to false in the rails config. This is the default in the development environment. What is difference then? When config.cache_classes is set to true (Default in production and test) then Rails eager loads the classes at startup. The class Tag gets loaded before TagTranslation and therefore globalize has already created a proxy class. So when our TagTranslation gets loaded it just reopens an existing class and adds stuff to it. What happens in development mode? Rails only loads models when triggered through Object.const_missing. When the constant Tag is referenced somewhere in the code, the class Tag is loaded and globalize creates a proxy class called TagTranslation as well as a has many association. The association normally triggers the associated class to be loaded (our TagTranslation model) but in this case, the class already exists and therefore our TagTranslation model never gets loaded.

How to fix it? I have a fork on github with a failing test and a fix: http://github.com/phuesler/globalize2. Alternatively you can make sure that your class gets loaded explicitly. You have to do this after you call globalize’s translate method. Here is how you could do it for the aforementioned Tag model:

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

When working on a new project I always make a few checks to get a feeling for the quality. Matthew Paul Moore has created a decent code quality checklist for Ruby on Rails applications.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]