Check your hashes

In this brief post I want to report a brief experiece regarding a Ruby 2.0+ feature.

A few weeks ago I wanted to enforce the name of the arguments accepted when initializing a simple PORO.

The object itself was pretty simple and its purpouse was to abstract the access and add some behavior to another one. Guess what, the encapsulated object was an Hash.

Thanks to the fact that I was on Ruby 2.0+ (specifically the last stable, i.e. 2.3.0) I immediately looked at keyword arguments.

This feature is already well known and there are actually many blog posts that describe how to use it. My favorite article is probably Justin’s post.

I’ll introduce some code I’ll explain later:

class Resource
  attr_reader :type, :id

  def initialize(resource_type:, resource_id:)
    @type = resource_type
    @id = resource_id

  %i[name description].each do |method|
    define_method(method) { instance.send method }

  def instance
    @instance ||= type.constantize.find(id)

  def permitted?
    permitted_types.include? type

  def not_permitted?

  def permitted_types

  def self.permitted_types
    %w[NewsItem Gate Course Document Gallery Video Survey Content]

In this example I’ve created a simple PORO which can be used to interact with different ActiveRecord resources such as NewsItem, Gate, Course, Document Gallery, Video, Survey and Content.

I wrote the code with some specs and so I felt I had my back somehow guarded.

Despite that, when I put the object in use, I stumbled in a banal ArgumentError. The code was actually a simple initialization of my object: home_block_params

I knew that home_block_params was an Hash and I also knew that it was composed by the expected key and value pairs, i.e. resource_type and resource_id.
You will probably have already realized what I clumsily missed: the nature of the Hash keys.
They were indeed strings while they had to be symbols!

I wrote some specs (just for fun ;)) to clear the things up:

describe '#initialize' do
  it 'raises an ArgumentError if no resource_type and resource_id arguments has been specified' do
    expect do raise_error(ArgumentError)

  it 'raises an ArgumentError if resource_type and resource_id arguments has been specified as strings' do
    expect do'resource_type' => 'News', 'resource_id' => 1) raise_error(ArgumentError)

  it 'does not raise any error if resource_type and resource_id arguments has been specified as strings' do
    expect do
    end.not_to raise_error

The quick solution in my case was to rely on Hash#symbolize_keys. Unfortunately this is something given by Ruby On Rails.

Anyway the take home message here is to properly refresh your memory when dealing with some midly new language features and to always consider the nature of Hash objects keys!

Leave a Reply