A Journey On Rails

Testing Rails exception handling

Posted in Rails, Testing by Vikram Venkatesan on December 23, 2009

I recently found a good article by Neeraj on rescue_action_in_public that saved a good amount of time for me while testing/modifying the rescue behaviour in ApplicationController.

But, testing it was not so trivial. Typicaly, the test.rb will be configuring all test requests to be considered local by through config.action_controller.consider_all_requests_local = true

Now, we need to override this setting only for a few test cases. Also, local_request? must be made to return false.
The former is quite straight forward, done by adding the following line of code to your test case.

@controller.consider_all_requests_local = false

For local_request? to return false, we must set @request.remote_addr to something other than 0.0.0.0 for the test framework to consider the request to be not local.
Rails provides a cleaner way to do this. Calling rescue_action_in_public! will do the job for us. So, putting the pieces together, here is a sample test code to get started

class DummyController < ApplicationController
  # Add actions for triggering different error cases (404 - Not Found, 403 - Forbidden, etc.,). Or have a single action and stub it.

  # Some dummy action throwing an exception
  def some_action
    raise "Some error"
  end
end

class ErrorHandlingTest < ActionController::TestCase
  tests DummyController

  def setup
    super
    @controller.consider_all_requests_local = false
    rescue_action_in_public!
  end

  def test_rescue_exception
    get :some_action
    # Assert the expected behaviour as follows
    #   assert_template "#{RAILS_ROOT}/app/views/common/500.html"
  end
end

Performance problems with AssociationCollection

Posted in Rails by Vikram Venkatesan on December 21, 2009

While debugging down some performance problem recently, i narrowed down the problem to a piece of code that iterated a has_many association using each method. To check whether the block passed to ‘each’ is the culprit, I emptied the block; that din’t help much. Finally i changed the call to AssociationCollecton.to_a#each, and groovy!, it reduced the time taken by that whole block by more than 10 times. Since that piece of code was called thousands of time in the request i was trying to optimize, it was an optimiziation in order of seconds for that request. What more would i ask?!

I took that chance to learn the AssociationProxy and AssocationCollection code to find what exactly was causing the delay. I learn’t that AssociationCollection delegats all unknown calls to it to @target, the actual collection Array, through method_missing. So, each call was also going through the method_missing path, creating so much delay. Following is a piece of code explains the above behaviour.

t = Time.now

# Replace with your real object and association
some_object.some_has_many_assoc.each { #empty}
puts &amp;quot;#{(Time.now - t) * 1000000} microseconds&amp;quot;

To validate my understanding, i tried some_object.some_has_many_assoc.send(:load_target).each{} , so as to call the ‘each’ method directly on the collection; that ran many times faster than the previous version.

I knew method_missing can lead to performance problems, but din’t expect it to happen at such a magnitude!