Строить маршруты поверх общего базового маршрута?

У меня есть общий базовый путь; сказать: get /base где мне нужно выполнить базовую аутентификацию и работать для всех дополнительных вызовов по этому пути. Сказать: get /base/foo а также get /base/bar,

Глядя на http://www.sinatrarb.com/intro.html предположить, что я смогу сделать это с помощью помощников. Я смотрел на pass помощник и использование call при запуске нового маршрута в документации. Но еще одно предложение, которое я прочитал, было использование динамической маршрутизации с использованием регулярных выражений IE %r{/base/?:(path)?} или что-то подобное. Так что насчёт:

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

Кто-нибудь имел дело с такими вещами раньше? Я пытаюсь держать это сухим. Конечно, я не уверен, что данный пример будет лучшим в сохранении параметров.

2 ответа

Решение

Есть несколько способов сделать это (они не в любом порядке, все хорошо):

Пространства имен с блоком before и помощником

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
      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

Пространство имен с условием

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 do
  authenticate!
    # funky auth stuff
    # but no need for `pass`
  end
end

before '/base/*' do
  authenticate!
end

сопоставленные приложения

class MyBase < Sinatra::Base
  helpers do
    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
#…

Я не уверен насчет необходимости высушивать маршруты, используя инструкцию case. Если каждый из маршрутов делает что-то свое, то я просто выписал бы их по отдельности, так как это намного понятнее, и вы дублируете работу, которую Синатра выполняет в сопоставлении маршрутов.

Как насчет использования before фильтры:

before '/base/?*' do
    @foo = 'bar'
end
Другие вопросы по тегам