Sinatra:模块化路由 class 无法识别辅助方法
Sinatra: modular routes class not recognizing helper methods
我正在用 Sinatra 构建一个 API,并且已经转换为模块化风格。但是,我遇到了无法识别路由文件中的方法调用的问题。
我简化了应用程序,因此 post 更短,但基本问题是如果我在 WorkoutHandler
中 GET /test
- 它无法识别 WardenStrategies
中的方法或 LoginHelper
除非我还将这些文件包含在处理程序中(它们已包含在 app.rb 中)。但是,一旦我这样做,他们使用的 gem 中声明的方法将无法识别。所有这些都在 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 文件。 (处理程序只是我用于 Controller/Route 文件的名称。
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
我假设 helpers
、use
和 register
只需要在 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
截至撰写本文时,运行ning 规范出现以下错误:
NoMethodError: undefined method `authenticated?' for nil:NilClass
这意味着 env 没有 :warden key/value(我在控制台中确认了这一点)。 authenticated?
方法在 Warden gem 目录中,所以我想我可以在每个 Handler 文件中 require 'warden'
- 我认为这不是构建模块化 Sinatra 应用程序的方式。
我已经阅读了所有关于模块化 Sinatra 应用程序的博客 post 和书籍章节,但我似乎无法调试我的问题。据我了解,需要在所有使用帮助程序的文件中重新注册(包括)帮助程序是无关紧要的。我认为通过扩展 Sinatra::Base,我可以访问 app.rb.
中声明的所有 类
如有任何帮助,我们将不胜感激。谢谢!
对您的问题的简短回答是,每次您子class Sinatra::Base,它都会创建一个完全独立的 Sinatra 应用程序。仅仅因为多个 classes subclass Sinatra::Base 并不意味着它们都继承了彼此的属性。这就是为什么它被称为 "modular" 风格!
如果您有一些共同的功能要在不同的 Sinatra 应用程序之间共享,您可以创建一个 mixin 并在每个应用程序中 extend/include 它(这基本上就是您现在使用 helpers
和 register
),或者您可以创建一个中间 class,您的应用程序子 class。例如:
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
至于你的问题 "Shouldn't this give my Handler access to gem methods?" 这取决于你的 Gemfile 是如何布局的。如果你有这样的事情:
gem 'sinatra', :require => 'sinatra/base'
gem 'sinatra-activerecord', :require => 'sinatra/activerecord'
gem 'warden'
那么是的,在您的 rackup 脚本中执行 Bundle.require
将消除在您的 class 文件中执行单独的 require
语句的需要。
我正在用 Sinatra 构建一个 API,并且已经转换为模块化风格。但是,我遇到了无法识别路由文件中的方法调用的问题。
我简化了应用程序,因此 post 更短,但基本问题是如果我在 WorkoutHandler
中 GET /test
- 它无法识别 WardenStrategies
中的方法或 LoginHelper
除非我还将这些文件包含在处理程序中(它们已包含在 app.rb 中)。但是,一旦我这样做,他们使用的 gem 中声明的方法将无法识别。所有这些都在 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 文件。 (处理程序只是我用于 Controller/Route 文件的名称。
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
我假设 helpers
、use
和 register
只需要在 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
截至撰写本文时,运行ning 规范出现以下错误:
NoMethodError: undefined method `authenticated?' for nil:NilClass
这意味着 env 没有 :warden key/value(我在控制台中确认了这一点)。 authenticated?
方法在 Warden gem 目录中,所以我想我可以在每个 Handler 文件中 require 'warden'
- 我认为这不是构建模块化 Sinatra 应用程序的方式。
我已经阅读了所有关于模块化 Sinatra 应用程序的博客 post 和书籍章节,但我似乎无法调试我的问题。据我了解,需要在所有使用帮助程序的文件中重新注册(包括)帮助程序是无关紧要的。我认为通过扩展 Sinatra::Base,我可以访问 app.rb.
中声明的所有 类如有任何帮助,我们将不胜感激。谢谢!
对您的问题的简短回答是,每次您子class Sinatra::Base,它都会创建一个完全独立的 Sinatra 应用程序。仅仅因为多个 classes subclass Sinatra::Base 并不意味着它们都继承了彼此的属性。这就是为什么它被称为 "modular" 风格!
如果您有一些共同的功能要在不同的 Sinatra 应用程序之间共享,您可以创建一个 mixin 并在每个应用程序中 extend/include 它(这基本上就是您现在使用 helpers
和 register
),或者您可以创建一个中间 class,您的应用程序子 class。例如:
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
至于你的问题 "Shouldn't this give my Handler access to gem methods?" 这取决于你的 Gemfile 是如何布局的。如果你有这样的事情:
gem 'sinatra', :require => 'sinatra/base'
gem 'sinatra-activerecord', :require => 'sinatra/activerecord'
gem 'warden'
那么是的,在您的 rackup 脚本中执行 Bundle.require
将消除在您的 class 文件中执行单独的 require
语句的需要。