Steffen Roller Steffen Roller -4 years ago 83
Ruby Question

Sinatra: params hash cannot be merged

I want to merge a hash with default parameters and the actual parameters given in a request. When I call this seemingly innocent script:

#!/usr/bin/env ruby

require 'sinatra'

get '/' do
defaults = { 'p1' => 'default1', 'p2' => 'default2' }
# params = request.params
params = defaults.merge(params)
params
end


with
curl http://localhost:4567?p0=request
then it crashes with

Listening on localhost:4567, CTRL+C to stop
2016-06-17 11:10:34 - TypeError - no implicit conversion of nil into Hash:
sinatrabug:8:in `merge'
sinatrabug:8:in `block in <main>'


When I access the Rack
request.params
directly it works. I looked into the Sinatra sources but I couldn't figure it out.

So I have a solution for my actual problem. But I don't know why it works.

My question is: Why can I assign
param
to a parameter, why is the class
Hash
but in
defaults.merge params
it throws an exception?

Any idea?

Answer Source

This is caused by the way Ruby handles local variables and setter methods (i.e. methods that end in =) with the same name. When Ruby reaches the line

params = defaults.merge(params)

it assumes you want to create a new local variable named params, rather than use the method. The initial value of this variable will be nil, and this is the value that the merge method sees.

If you want to refer to the method, you need to refer to it as self.params=. This is for any object that has such a method, not just Sinatra.

A better solution, to avoid this confusion altogether, might be to use a different name. Something like:

get '/' do
  defaults = { 'p1' => 'default1', 'p2' => 'default2' }
  normalized_params = defaults.merge(params)
  normalized_params.inspect
end
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download