Skip to content

Instantly share code, notes, and snippets.

@tonyta
Last active August 29, 2015 14:05
Show Gist options
  • Save tonyta/ad5557e97687a59af13e to your computer and use it in GitHub Desktop.
Save tonyta/ad5557e97687a59af13e to your computer and use it in GitHub Desktop.

Keyword Args and Hash-types

TLDR: keyword arguments only with with symbol-keyed hashes but DON'T symbolize keys on params unless you know what you're doing.

Ruby's keyword arguments only work with Hash objects where all of the keys are symbols.

They do not with:

  • ActionController::Parameters
  • ActiveSupport::HashWithIndifferentAccess

HashWithIndifferentAccess (as well as its decendant Parameters) stores its keys as strings and will throw an error if passed into a method expecting keyword arguments.

RUBY_VERSION     #=> "2.1.2"

require 'action_controller'
require 'active_support/core_ext'

normal_hash = { a: 'potato', name: 'Stanley Pickles' }
indiff_hash = normal_hash.with_indifferent_access
params_hash = ActionController::Parameters.new(normal_hash)

def foo(a: '1', b: '2', **args)
  [a, b, args]
end

foo              #=> ["1", "2", {}]
foo(nil)         # ArgumentError: wrong number of arguments (1 for 0)
foo({})          #=> ["1", "2", {}]

foo(normal_hash) #=> ["potato", "2", {:name=>"Stanley Pickles"}]
foo(indiff_hash) # ArgumentError: wrong number of arguments (1 for 0)
foo(params_hash) # ArgumentError: wrong number of arguments (1 for 0)

Workaround

A workaround is just to call #symolize_keys from ActiveSupport's Core Extension.

Security Vunerability with Params

This should never be called on request params in Rails, however, since it opens a vulnerability to DoS attacks. A malicious user can potentially pass parameters with millions of different keys which stay in memory since symbols in Ruby pre-2.2 are never garbage collected.

The solution is to create a new Hash or hash-like object with only the specific keys you need using #slice (ActiveSupport Core Extension), #permit (ActionController), #keep_if (Ruby Core), etc. and then call #symbolize_keys on the resulting object.

Sources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment