Make Array#collect return a hash

The Array#collect method is great for taking a hash or an array of objects and returning a new array based on the block you provide it, but sometimes you'd like to return a hash instead of an array. My primary use case for this is in testing Rails form posts with checkboxes. For instance, here is some HTML source of an imaginary page:

<form action="/people/update_item_status/1" method="post">
  <input type="checkbox" name="items[1]" /> Car
  <input type="checkbox" name="items[3]" /> Laptop
  <input type="checkbox" name="items[7]" /> Television
  <input type="submit" value="Update Status" />
</form>

When submitted to Rails with "Car" and "Television" checked, the above form should come over like this:

Processing PeopleController#update_item_status 
  (for 127.0.0.1 at 2007-02-11 17:00:41) [POST]
  Session ID: asdf
  Parameters: {"controller"=>"people", "action"=>"update_item_status", 
    "id"=>"1",  "items" => {"1" => "1", "7" => "1"}}

When testing, you might want to build the items hash based on any number of items you specify. Using Array#collect, you'll get back an array, which won't work when building the params hash. What you need is something like the following:

module Enumerable
  # Usage: items.build_hash { |item| [ item.id, 1 ] } => { 1 => 1, 7 => 1, … }
  def build_hash
    returning(result = {}) do
      self.each do |pair|
        key, value = yield(pair)
        result[key] = value
      end
    end
  end
end

It's probably worth noting that the returning method is something included in Rails, so if you're not using this method inside a Rails project, you can either change the code to declare result = {} and then return result at the end of the method, or add the following code somewhere in your project:

class Object
  def returning(value)
    yield(value)
    value
  end
end

One Response to “Make Array#collect return a hash”

  1. Beirdo Says:

    Thank you. This worked splendidly for me. I was reimplementing some settings that I had as a hash in the session, moving it to the database. Now with your build_hash method, I can directly build an equivalent hash from the database. Much appreciated.

Leave a Reply