首页 文章

Sinatra:模块化路由类不识别辅助方法

提问于
浏览
0

我正在Sinatra中构建一个API,并已转换为模块化样式 . 但是,我遇到的问题是路由文件中的方法调用无法识别 .

我已经简化了应用程序,因此帖子更短,但基本问题是,如果我 WorkoutHandler - 它无法识别 WardenStrategiesLoginHelper 中的方法,除非我还在Handler中包含这些文件(它们已包含在app.rb中) . 但是,一旦我这样做,他们使用的宝石中声明的方法就无法识别 . 所有这些都在app.rb中注册,并且在我的Rackup文件中是必需的 .

这是我的app.rb文件

require 'sinatra/base'
require 'sinatra/activerecord'

class WorkoutApp < Sinatra::Base

  register Sinatra::ActiveRecordExtension
  register WardenStrategies

  use WorkoutHandler

  helpers LoginHelper
  helpers HashHelpers

  use Rack::Session::Cookie
  use Warden::Manager do |manager|
    manager.default_strategies :password
    manager.intercept_401 = false
    manager.failure_app = WorkoutApp
    manager.serialize_into_session(&:id)
    manager.serialize_from_session { |id| User.find(id) }
  end
  set :database_file, '../config/database.yml'

  Warden::Manager.before_failure do |env, _opts|
    env['REQUEST_METHOD'] = 'POST'
  end
end

这是config.ru,Handler和Helper文件 . (处理程序只是我用于控制器/路径文件的名称 .

module LoginHelper
  def warden_handler
    env['warden']
  end

  def current_user
    warden_handler.user
  end

  def check_authentication
    return if warden_handler.authenticated?
    body 'User not authenticated'
    halt 401
  end
end

我假设 helpersuseregister 只需要在app.rb中声明(因为我需要我的rackup文件中的所有文件并从那里运行应用程序) . 但是,除非我在这里注册帮助程序,否则无法识别 check_authentication 方法 .

class WorkoutHandler < Sinatra::Base
  helpers LoginHelper                   # Is there a way to not need this?
  register WardenStrategies             # Or this?

  get '/test' do
    check_authentication
  end
end

module WardenStrategies
  Warden::Strategies.add(:password) do
    def valid?
      params['email'] || params['password']
    end

    def authenticate!
      user = User.find_by(email: params['email'])
      if user && user.authenticate(params['password'])
        success!(user)
      else
        fail!('Could not log in')
      end
    end
  end
end

require 'rubygems'
require 'bundler'

Bundler.require     #Shouldn't this give my Handler access to gem methods?

ENV['APP_NAME'] = 'workout'

require_all 'app'

run WorkoutApp

截至撰写本文时,我在运行规范时遇到以下错误:

NoMethodError: undefined method `authenticated?' for nil:NilClass

这意味着env没有:warden键/值(我在控制台中确认) . authenticated? 方法在Warden gem目录中,所以我想我可以在每个Handler文件中使用 require 'warden' - 我不应该像模块化的Sinatra应用程序那样构建 .

我已经阅读了所有关于模块化Sinatra应用程序的博客文章和书籍章节,我似乎无法调试我的问题 . 根据我的理解,需要在使用它们的所有文件中重新注册(包括)帮助程序是无关紧要的 . 我认为通过扩展Sinatra :: Base,我可以访问app.rb中所有声明的类 .

任何帮助,将不胜感激 . 谢谢!

1 回答

  • 1

    对你的问题的简短回答是,每次你将Sinatra :: Base子类化时,它都会创建一个完全独立的Sinatra应用程序 . 仅仅因为多个类子类Sinatra :: Base并不意味着它们都继承了彼此的属性 . 这就是它被称为“模块化”风格的原因!

    如果你有一些共同的功能可以在不同的Sinatra应用程序之间共享,你可以创建一个mixin并在每个应用程序中扩展/包含它(这基本上就是你现在使用的 helpersregister ),或者你可以创建一个中间体您的应用程序子类的类 . 例如:

    my_base_app.rb:

    require 'sinatra/base'
    require 'warden'
    
    require_relative 'login_helper'
    
    class MyBaseApp < Sinatra::Base
      register WardenStrategies
    
      helpers LoginHelper
    end
    

    workout_app.rb:

    require 'sinatra/activerecord'
    require 'warden'
    
    require_relative 'my_base_app'
    require_relative 'hash_helpers'
    require_relative 'workout_handler'
    
    class WorkoutApp < MyBaseApp
      register Sinatra::ActiveRecordExtension
    
      use WorkoutHandler
    
      helpers HashHelpers
    
      use Rack::Session::Cookie
      use Warden::Manager do |manager|
        # yadda yadda...
      end
    end
    

    workout_handler.rb:

    require_relative 'my_base_app'
    
    class WorkoutHandler < MyBaseApp
      get '/test' do
        check_authentication
      end
    end
    

    至于你的问题“这不应该让我的处理程序访问gem方法吗?”这取决于你的Gemfile的布局方式 . 如果您有这样的事情:

    gem 'sinatra', :require => 'sinatra/base'
    gem 'sinatra-activerecord', :require => 'sinatra/activerecord'
    gem 'warden'
    

    然后是的,在你的rackup脚本中执行 Bundle.require 将无需在类文件中执行单独的 require 语句 .

相关问题