Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Build routes on top of a common base route?

I have a common base path; say: get /base where I need to have basic auth performed and working for all sub calls under that path. Say: get /base/foo and get /base/bar.

Looking at http://www.sinatrarb.com/intro.html#Helpers suggests I should be able to do this with the use of helpers. I was looking at the pass helper and use of call under triggering a new route in the documentation. But, another suggestion I read was using dynamic routing using regexes IE %r{/base/?:(path)?} or some such. So what about:

def '/base'
    # do some funky basic auth stuff here
    # to work with all request to this common
    # base path?
    pass
end

def %r{/base/?(path)?} do |path|
    case path
        when 'foo'
            # do something.
        when 'bar'
            # do something else.
    end

    # some kind of redirection or template rendering here:
    erb :template
end

Has anyone dealt with this kind of thing before? I'm trying to keep it DRY. Of course, I'm not sure the given example would be the best in preserving params.

like image 753
Jim Avatar asked Mar 29 '13 01:03

Jim


2 Answers

There are a few ways you could do this (these aren't in any order, they're all good):

Namespaces with a before block and a helper

http://rubydoc.info/gems/sinatra-contrib/1.3.2/Sinatra/Namespace

require 'sinatra/namespace'

class App < Sinatra::Base
  register Sinatra::Namespace

  namespace "/base" do
    helpers do # this helper is now namespaced too
      def authenticate!
      # funky auth stuff
      # but no need for `pass`
      end
    end

    before do
      authenticate!
    end
  
    get "/anything" do
    end

    get "/you" do
    end

    get "/like/here" do
    end
  end

Namespace with a condition

require 'sinatra/namespace'

class App < Sinatra::Base
  register Sinatra::Namespace

  set(:auth) do |*roles|   # <- notice the splat here
    condition do
      unless logged_in? && roles.any? {|role| current_user.in_role? role }
        redirect "/login/", 303
      end
    end
  end

  namespace "/base", :auth => [:user] do
    # routes…
  end

  namespace "/admin", :auth => [:admin] do
    # routes…
  end

Helpers and a before filter

helpers do
  def authenticate!
    # funky auth stuff
    # but no need for `pass`
  end
end

before '/base/*' do
  authenticate!
end

mapped Apps

class MyBase < Sinatra::Base
  helpers do
    def authenticate!
      # funky auth stuff
      # but no need for `pass`
    end
  end

  before do
    authenticate!
  end

  get "/" do
  end
  get "/another" do
  end
end

# in rackup file

map "/" do
  run App1
end
map "/base" do
  # every route in MyBase will now be accessed by prepending "/base"
  # e.g. "/base/" and "/base/another"
  run MyBase
end
#…

I'm not sure about the need to DRY up routes using a case statement. If the routes each do something different then I'd just write them out separately as it's a lot clearer and you're duplicating the work Sinatra does in matching routes.

like image 110
ian Avatar answered Nov 08 '22 19:11

ian


How about using before filters:

before '/base/?*' do
    @foo = 'bar'
end
like image 35
Arman H Avatar answered Nov 08 '22 20:11

Arman H