Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Altering params in Sinatra before blocks

Tags:

ruby

sinatra

I am trying to alter the request params in a before block in Sinatra.

It seems that when using this syntax, it works:

before do
  @params['global-before'] = 'yes'
end

But when using this syntax, it does not work:

before '/:id/test' do
  @params['route-before'] = 'yes'
end

Here is a full example:

# test.rb
require 'sinatra'
require 'sinatra/reloader'

set :bind, '0.0.0.0'
set :port, 3000

before do
  @params['global-before'] = 'yes'
end

before '/:id/test' do
  @params['route-before'] = 'yes'
end

get '/' do
  params.to_json
end

get '/:id/test' do
  params.to_json
end

Then running:

$ ruby test.rb

$ curl localhost:3000
{"global-before":"yes"}

$ curl localhost:3000/123/test
{"global-before":"yes","id":"123"}

I was expecting to see the params['route-before'] populated as well.

I have tried using request.params instead of @params but that did not work at all.

Can anyone shed some light on this?

Update:

Opened an issue in Sinatra's issue tracker

like image 449
DannyB Avatar asked Jun 04 '26 15:06

DannyB


1 Answers

The route filter goes first, and it has route parameters: {"id"=>"123"}, so this happens:

original, @params = @params, @params.merge(params) if params.any?

where original ends up as {} and @params as {"id"=>"123"}. When the global filter runs, there are no route parameters, so original remains unassigned (nil) and @params is the {} that was originally there.

After the filter processes, in the ensure clause, there is this:

@params = original if original

So global filter skips it, because original is nil, because there were no route parameters. The route filter resets the @params to whatever it was before the filter ran, because original is preserved, because there were route parameters.

I can't say whether this is a bug or an intended behaviour, but it's a "how" at least, if not a "why". It may make sense asking the Sinatra team (and reporting back here with the verdict).

tl;dr: @params are reset to pre-filter state if there are parameters in the filter's path pattern.

Note: you can hack around it by making your own instance variable:

before '/:id/test' do
  @route_before = 'yes'
end

get '/:id/test' do
  "Did we run route before? #{@route_before}"
end
like image 151
Amadan Avatar answered Jun 07 '26 07:06

Amadan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!