Tyler A
Tyler A

Reputation: 23

Halt in Before filter still proceeds to After filter

So my understanding is that the halt command should stop the request in the current filter, but it appears to continue on. What follows is a very simple Sinatra app demonstrating this.

server.rb

require 'sinatra'

before do
  puts "before halt"
  halt 401
  puts "after halt"
end

before '/partners*' do
  puts "i am in before /partners"
end

after '/partners*' do
  puts "i am in after /partners"
end

get '/partners/v1/:public_id' do
  puts "i am in the actual route"
end

I am calling 'get' on the following location: localhost:4567/partners/v1/111
What I expect to output:

before halt

What is actually outputting:

before halt
i am in after /partners

So my question's are exactly:
1. Why does the halt continue on at all (shown with it reaching after '/partners*')
2. Why does it hit the after '/partners*' but not the before '/partners*'

Upvotes: 2

Views: 531

Answers (1)

ian
ian

Reputation: 12251

Here is the code for halt and here is the code for invoke, and just below invoke is the method declaration for dispatch!

As you can see, dispatch! calls invoke, which runs the route block with support for halting. It also runs the :before filter in the invoke block.

invoke do
  static! if settings.static? && (request.get? || request.head?)
  filter! :before
  route!

So you can halt inside a before filter and it won't reach the route, which is why you don't see any output from your route block.

However, the dispatch! method also has an ensure:

ensure
  begin
    filter! :after unless env['sinatra.static_file']

An ensure does what it says, it will always be evaluated. This is why the after '/partners*' block is processed. This is expected behaviour (as it's coded quite clearly that way). Basically, if you put in an after block, it will get processed, regardless of halts in before filters or route blocks.

From the docs:

Routes are matched in the order they are defined. The first route that matches the request is invoked.

and

…filters are evaluated before each request within the same context as the routes

Now, the docs aren't explicit about this, but if you add the two quotes together I'd take that to mean "Filters are matched in the order they are defined." Basically, because it fits the actual behaviour.

All the before filters should run, but you put a halt in the first one, so the second one (before '/partners*') doesn't run.

Upvotes: 1

Related Questions