Sinatra: Unexpected param parsing with optional url parameters

Created on 10 Nov 2017  路  5Comments  路  Source: sinatra/sinatra

While investigating https://github.com/sinatra/sinatra/issues/1361 I found the following which I think is a separate issue. Since this issue also occurs in Sinatra 1.4.8 I don't know if this is by design or not, but imho it leads to unexpected behaviour.

I think it boils down to the fact that Sinatra should let the most specific route match do the parameter parsing and use those parsed values for the filters (like before). Not doing so will cause possible different param values for the same param in filters (before) and the verbs (get, post etc)

Testcase:

require 'minitest/autorun'
require 'sinatra/base'
require 'rack/test'

VALUES = {}

class App < Sinatra::Base

  before '/foo/:bar/?:baz?' do
    VALUES[:before] = params[:baz]
  end

  get '/foo/:bar/?:baz?/1' do
    VALUES[:get] = params[:baz]
  end
end

class NestedNamespacesTest < Minitest::Test
  include Rack::Test::Methods

  def app
    App
  end

  def test_same_values
    get "/foo/2017/1"
    assert_equal VALUES[:before], VALUES[:get]
  end
end

This test will fail, meaning that in the before filter baz yields to 1 but in the actual route it is nil.

help wanted

Most helpful comment

I think this is not a bug, but I'd like to keep this issue for discussing the API-design.
@lvonk Thanks for your report.

cc @zzak

All 5 comments

First of all, you should use (/:bar)? as an optional parameter instead of :bar/?.
The captured name depends on the context. Therefore, I think the behavior is not a bug.

Hi @namusyaka thanks for replying. The optional parameter is baz in the example, not bar. '/foo/:bar/?:baz?' (my apologies for the confusing names in the example). Both ways of defining an optional parameter seem to work the same /?:baz? versus (/?:baz)?. Changing to (/?:baz)? does not result in a different outcome.

The captured name depends on the context

I would argue the context is the most specific route. In fact that is also what the readme states (or at least that is how I interpret it):

Before filters are evaluated before each request within the same context as the routes will be and can modify the request and response.

Bug or not, IMHO it makes most sense that filters work from within that context. I can't think of a context or situation where I do want param values to differ between filter and route?

The optional parameter is baz in the example, not bar. '/foo/:bar/?:baz?' (my apologies for the confusing names in the example). Both ways of defining an optional parameter seem to work the same /?:baz? versus (/?:baz)?. Changing to (/?:baz)? does not result in a different outcome.

Sorry for your confusing. I wanted to say that the optional parameter should be (/:foo)?, please see mustermann's readme.

Bug or not, IMHO it makes most sense that filters work from within that context. I can't think of a context or situation where I do want param values to differ between filter and route?

Actually the patterns in the route and the filter are not necessarily closely related.
This behavior is established.

Actually the patterns in the route and the filter are not necessarily closely related.
This behavior is established.

Hmm okay. I did not consider that. It still feels strange though to have a param's value differ in a filter and route in a single request...

Well anyway if this is the way it should work, than indeed it is not a bug. Thanks for taking the time to look into this! Feel free to close this issue if you consider it handled.

I think this is not a bug, but I'd like to keep this issue for discussing the API-design.
@lvonk Thanks for your report.

cc @zzak

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fullofcaffeine picture fullofcaffeine  路  7Comments

GCorbel picture GCorbel  路  7Comments

ricardovsilva picture ricardovsilva  路  7Comments

za3k picture za3k  路  5Comments

nickpelone picture nickpelone  路  5Comments