May 28, 2015 by Daniel P. Clark

Rails’ HashWithIndifferentAccess

A Ruby Hash is a very powerful collection type to use in Ruby.  When working in Rails sometimes you’ll have symbols as keys or sometimes they will be strings.  If you use a normal Hash these will store as different keys for the same name.

sample = Hash.new
sample[:a] = 1
sample["a"] = 2
sample
# => {:a=>1, "a"=>2}

Rails has another version of Hash that will map strings and symbols as the same kind of key: HashWithIndifferentAccess .  So you don’t have to worry about any possible mixup, especially when handling Rails form parameters.

sample2 = HashWithIndifferentAccess.new
sample2[:a] = 1
sample2["a"] = 2
sample2
# => {"a"=>2}

When you use Rails it add additional methods to both the traditional Hash Object and HashWithIndifferentAccess.

Lets say you’re writing a helper method for a form that updates an object and you want to allow people to overwrite the form_for options.

# some_helper.rb
def form_for_update_helper(options = {})

  options = HashWithIndifferentAccess.new(options)

  defaults = {
    method: :patch,
    remote: true,
    authenticity_token: true
  }

  options.reverse_merge!(defaults)
end

# controller for form
def view
  @thing = Thing.find(thing_params[:id])
  @form_for_options = form_for_update_helper
end

# some view partial
<%= form_for(@thing, **@form_for_options.symbolize_keys) do |f| %>

reverse_merge! will add any key value pairs that don’t exist within the Hash you are calling it on.  In the helper method above we first convert any incoming Hash to a HashWithIndifferentAccess type.  We then define our defaults for this Hash and we update it with reverse_merge! .  In the controller we may add any extra options if we’d like; such as form_for_update_helper( url: comment_path ).  And in the view the double star is the keyword expansion method.  So the **@form_for_options.symbolize_keys changes into the parameters method: :patch, remote: true, authenticity_token: true for out form_for method.

It’s important to use the symbolize_keys method when expanding into keyword args as the HashWithIndifferentAccess defaults its keys to Strings and that will not work as form_for parameters.

If you’d like to see this code in use I’ve implemented it in Dynaspan 0.1.2 beta1 .  There are plenty of other cool things you can do with this, but I’ve shown what I like most with HashWithIndifferentAccess .  If you’re interested in more details on Ruby Collection Types feel free to read my other post.

Summary

I love this collection type simply for its simplicity and less error prone convenience.  Know any other cool things you can do with HashWithIndifferentAccess ?  Then feel free to comment about it below.

Please feel free to comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!

God Bless!
-Daniel P. Clark

Image by Michael Coghlan via the Creative Commons Attribution-ShareAlike 2.0 Generic License

#hash#hashwithindifferentaccess#rails#reverse_merge#ruby on rails

Leave a Reply

Your email address will not be published / Required fields are marked *