Returning Enumerator unless block_given?

The Enumerable module gives you methods to search, iterate, traverse and sort elements of a collection. All you need to to is to implement each and include the mixin.

class NameList
  include Enumerable

  def initialize(*names)
    @names = names
  end

  def each
    @names.each { |name| yield(name) }
  end
end

list = NameList.new('Kaiser Chiefs', 'Muse', 'Beck')

list.each_with_index do |name, index|
  puts "#{index + 1}: #{name}"
end

# => 1: Kaiser Chiefs
# => 2: Muse
# => 3: Beck

So by defining each and including Enumerable we got an impressive list of methods that we can call on our NameList instance. But having all those methods added does not feel right. Usually you will use one or two of them. Why clutter the interface by adding 50+ methods that you’ll never use? There is an easy solution for this:

class NameList
  def initialize(*names)
    @names = names
  end

  def each
    return @names.to_enum(:each) unless block_given?
    @names.each { |name| yield(name) }
  end
end

list = NameList.new('Kaiser Chiefs', 'Muse', 'Beck')

list.each do |name|
  puts name
end
# => Kaiser Chiefs
# => Muse
# => Beck

list.each.each_with_index do |name, index|
  puts "#{index + 1}: #{name}"
end
# => 1: Kaiser Chiefs
# => 2: Muse
# => 3: Beck

Note that each now returns the Enumerator on which you can call each_with_index (or any of the other methods) unless a block is given. So you can even call it like this:

puts list.each.to_a.size
# => 3

By returning an Enumerator when no block is given one can chain enumerator methods. Ever wanted to do a each_with_index on a hash? There you go:

points = {mushroom: 10, coin: 12, flower: 4}
points.each.each_with_index do |key_value_pair, index|
  puts "#{index + 1}: #{key_value_pair}"
end

# => 1: [:mushroom, 10]
# => 2: [:coin, 12]
# => 3: [:flower, 4]

Ruby and the double splat operator

If you have been programming ruby for a while then you have seen the splat operator. It can be used to define methods that accept a variable length argument list like so:

def single_splat(an_argument, *rest)
 puts "#{rest.size} additional argument(s)"
end

single_splat('howdy')
#=> 0 additional argument(s)

single_splat('howdy', :foo)
#=> 1 additional argument(s)

single_splat('howdy', :foo, :bar, :baz)
#=> 3 additional argument(s)

But also to “unwrap” values from an array and pass them as single arguments:

def unwrapped(a, b, c)
 puts "#{a} / #{b} / #{c}"
end

data = [1, 2, 3]

unwrapped(*data)
# => 1 / 2 / 3

unwrapped(data)
#=> wrong number of arguments (1 for 3) (ArgumentError)

But behold can use the splat operator also to coerce values into arrays:

coerced = *"Hello World"
p coerced
# => ["Hello World"]

coerced = *nil
p coerced
# => []

coerced = *[1, 2, 3]
p coerced
# => [1, 2, 3]

And of course to deconstruct arrays:

data = [1, 2, 3, 4]

first, *rest = data
puts "#{first}, #{rest}"
# => 1, [2, 3, 4]
*list, last = data
puts "#{list}, #{last}"
# => [1, 2, 3], 4

first, *center, last = data
puts "#{first}, #{center}, #{last}"
# => 1, [2, 3], 4

first, second, *center, third, fourth = data
puts "#{first}, #{second}, #{center}, #{third}, #{fourth}"
# => 1, 2, [], 3, 4

But now back to the double splat operator. It has been added to Ruby in version 2.0 and behaves similarly to the single splat operator but for hashes in argument lists:

def double_splat(**hash)
 p hash
end

double_splat()
# => {}

double_splat(a: 1)
# => {:a => 1}

double_splat(a: 1, b: 2)
# => {:a => 1, :b => 2}

double_splat('a non hash argument')
# => `double_splat': wrong number of arguments (1 for 0) (ArgumentError)
# (The message for the case where I pass in a non-hash argument is not very helpful i'd say)

“What!” i can hear you shout. Where is the difference to a standard argument. In the use case as shown above it is pretty much the same. But you would be able to pass in nil values or non hash values, so more checks would be required:

def standard_argument(hash = {})
 puts hash
end

standard_argument()
# => {}

standard_argument(nil)
# =>

Now if we move this to a more realistic use case, consider a method taking a variable list of arguments AND some options:

def extracted_options(*names, **options)
 puts "#{names} / #{options}"
end

extracted_options()
# => [] / {}

extracted_options('pascal', 'lukas', color: '#123456', offset: 3, other_option: :foo)
# => ["pascal", "lukas"] / {:color=>"#123456", :offset=>3, :other_option=>:foo}

Ruby on Rails developers might know this pattern already. It is used in various parts of the framework. It is so common that the functionality has been defined in extract_options!

Handling errors in Ruby on Rails

Rails offers multiple ways to deal with exceptions and depending on what you want to achieve you can pick either of those solutions. Let me walk you through the possibilities.

begin/rescue block

begin/rescue blocks are the standard ruby mechanism to deal with exceptions. It might look like this:

begin
  do_something
rescue
  handle_exception
end

This works nice for exceptions that might happen in your code. But what if you want to rescue every occurrence of a specific exception, say a NoPermissionError which might be raised from your security layer? Clearly you do not want to add a begin/rescue block in all your actions just to render an error message, right?

Around filter

An around filter could be used to catch all those exceptions of a given class. Honestly I haven’t used a before filter for this, this idea came to my mind when writing this blog post.

class ApplicationController < ActionController::Base
  around_action :handle_exceptions

  private
  def handle_exceptions
    begin
      yield
    rescue NoPermissionError
      redirect_to 'permission_error'
    end
  end
end

rescue_from

rescue_from gives you the same possibilities as the around filter. It’s just shorter and easier to read and if the framework offers a convenient way, then why not use it. There are multiple ways to define a handler for an exception, for a short and sweet handler I prefer the block syntax:

class ApplicationController < ActionController::Base
 rescue_from 'NoPermissionError' do |exception|
   redirect_to 'permission_error'
 end
end

exceptions_app

There is an additional feature (added in Rails 3.2) that allows to handle exceptions. You can specify an exceptions_app which is used to handle errors. You can use your own Rails app for this:

config.exceptions_app = self.routes

If you do so, then your routing must be configured to match error codes like so:

match '/404', to: 'exceptions#handle_404'
...

Alternatively you can specify a lambda which receives the whole Rack env:

config.exceptions_app = lambda do |env|
  # do something
end

Do you wonder how you can call an arbitrary action when you have the env? It’s pretty easy:

action = ExceptionsController.action(:render_error)
action.call(env)

In any case you want to set following configuration for exceptions_app to be used:

Rails.application.config.consider_all_requests_local = false
Rails.application.config.action_dispatch.show_exceptions = true

But where is the exception you ask? It is stored in the Rack env:

env[<span class="pl-s1"><span class="pl-pds">'</span>action_dispatch.exception<span class="pl-pds">'</span></span>]

And as a bonus: here is how you can determine an appropriate status code for an exception:

wrapper = <span class="pl-s3">ActionDispatch</span>::<span class="pl-s3">ExceptionWrapper</span>.<span class="pl-k">new</span>(env, exception)
wrapper.status_code

There is more information you can extract using the exception wrapper. Best you look it up in the API description.

Most of this code can be seen in action in our infrastructure gem which we use to add error pages to apps we build.

How we sped up our model spec to run 12 times faster

We are using cancancan as an authorization gem for one of our applications. To make sure that our authorization rules are correct, we unit-tested the Ability object. In the beginning, the test was quite fast, but the more rules we added, the longer it took to run the whole model test.
When we analyzed what was slowing down our test, we saw that quite some time is actually used persisting our models to the database with factory_girl as part of the test setup. It took a bit more than 60 seconds to run the whole ability spec, which is far too much for a model test.

Let’s look at an excerpt of our ability and its spec:


# ability.rb

def acceptance_modes
  can [:read], AcceptanceMode
  if @user.admin?
    can [:create, :update], AcceptanceMode
    can :destroy, AcceptanceMode do |acceptance_mode|
      acceptance_mode.policies.empty?
    end
  end
end


# ability_spec.rb

describe Ability do

  let!(:admin_user) { create(:admin_user) }
  subject!(:ability) { Ability.new(admin_user) }

  context 'acceptance mode' do

    let!(:acceptance_mode) { create(:acceptance_mode) }

    before(:each) do
      create(:policy, :acceptance_mode => acceptance_mode)
    end

    [:read, :create, :update].each do |action|
      it { should be_able_to(action, acceptance_mode) }
    end

    it { should_not be_able_to(:destroy, acceptance_mode) }

  end
end


# ability_matcher.rb

module AbilityHelper
  extend RSpec::Matchers::DSL

  matcher :be_able_to do |action, object|
    match do |ability|
      ability.can?(action, object)
    end

    description do
      "be able to #{action} -- #{object.class.name}"
    end

    failure_message do |ability|
      "expected #{ability.class.name} to be able to #{action} -- #{object.class.name}"
    end

    failure_message_when_negated do |ability|
      "expected #{ability.class.name} NOT to be able to #{action} -- #{object.class.name}"
    end
  end
end

RSpec.configure do |config|
  config.include AbilityHelper
end

We first set up a user — in this case it’s an admin user — and then initialize our ability object with this user. We further have a model called AcceptanceMode, which offers the usual CRUD operations. An acceptance mode has many policies. If any policy is attached to an acceptance mode, we don’t want to allow it to be deleted.

Note that a lot of models are created, meaning these are persisted to the database. In this excerpt, we have 4 test cases. Each of these test cases needs to create the admin user, acceptance mode and also create a policy. This is a lot of persisted models, even more so if you realize that this is not all the acceptance mode specs and acceptance mode specs are only a small fraction of the whole ability spec. Other models are even more complex and require more tests for other dependencies.

But is this really necessary? Do we really need to persist the models or could we work with in-memory versions of these?

Let’s take a look at this modified spec:


describe Ability do

  let(:stub_policy) { Policy.new }
  let!(:admin_user) { build(:admin_user) }
  subject!(:ability) { Ability.new(admin_user) }

  context 'acceptance mode' do

    let(:acceptance_mode) { build(:acceptance_mode, :policies => [stub_policy]) }

    [:read, :create, :update].each do |action|
      it { should be_able_to(action, acceptance_mode) }
    end

    it { should_not be_able_to(:destroy, acceptance_mode) }

  end
end

Note that all the create calls are replaced with build. We actually don’t need the models to be persisted to the database. The ability mainly checks if the user has admin rights (with admin?), which can be tested with an in-memory version of a user. Further, the acceptance mode can be built with an array that contains an in-memory stub policy. If you look closely at the Ability implementation, you will see that that’s not even necessary. Any object could reside in the array and the spec would still pass. But we decided to use an in-memory policy nonetheless.

With this approach, no model is persisted to the database. All models are in-memory but still collaborate the same way as they would have when loaded from the database first. However, no time is wasted on the database. The whole ability spec run time was reduced from 60 seconds to 5 seconds, by simply avoiding to persist models to the database in the test setup.

As an aside: there’s a lot of discussions around the topic of factories and fixtures. Fixtures load a fixed set of data into the database at the start of the test suite, which avoids these kinds of problems entirely.

That’s it. We hope you can re-visit some of your slow unit tests and try to use in-memory models, or avoid persisting your models for the next unit test you write!