我有一个Sinatra应用程序,它安装在/admin
下的Rails应用程序中。 Sinatra应用程序是一个管理仪表板,因此只应供授权用户使用。
为了强制执行,我构建了一个Rack Sinware,它将在调用Sinatra应用程序之前运行。
逻辑很简单 -
以下代码。我觉得我在redirect
方法中遗漏了一些东西。 Rack::Builder
块构建一个mini-Rack应用程序,并且内部的块进一步创建另一个Rack应用程序(Proc),它使用flash消息构建重定向响应。
当我运行它时,我得到undefined method 'detect' for nil:NilClass
,这表示两个块都没有返回有效的非nil
响应。我是否需要在其中一个块上的某个地方运行call
?
如果有帮助,我正在使用Puma Web服务器。
谢谢!
require "rack"
require "rack-flash"
class AdminAuthorizer
def initialize(app)
@app = app
end
def call(env)
@env = env
id = @env["rack.session"][:user_id]
user = User.where(id: id).first
# Check if user is authorized, otherwise redirect
user.admin? ? ok : redirect
end
private
def ok
@app.call(@env)
end
def redirect
Rack::Builder.new do
use Rack::Flash, sweep: true, accessorize: true
run(
Proc.new do |env|
env["x-rack.flash"].alert = "Insufficient permissions"
res = Rack::Response.new
res.redirect("/")
res.finish
end
)
end
end
end
答案 0 :(得分:2)
好吧,我自己想到了其他任何好奇的人。
我必须使用{mid}感知support
使用的env
密钥'action_dispatch.request.flash_hash'
我没有必要使用rack-flash
宝石,虽然我确信在构建Sinatra应用程序时仍然有用
注意:这是在Rails v4.2.4上。我相信自Flash
模块发生了一些变化,因此我不知道该密钥是否已更改。但您可以通过搜索最新的回购来确认类似的定义。
require "rack"
class AdminAuthorizer
FLASH = ActionDispatch::Flash
def initialize(app)
@app = app
end
def call(env)
@env = env
id = @env["rack.session"][:user_id]
user = User.where(id: id).first
# Check if user is authorized, otherwise redirect
user.admin? ? ok : redirect
end
private
def ok
@app.call(@env)
end
def redirect
# Calls a Rack application (the defined Proc). If you want to do more steps
# or get fancier, you can wrap this in a Rack::Builder call
#
# Rack::Builder.app(redirect_proc)
# use (blah)
# run (blah)
# end.call(@env)
#
redirect_proc.call(@env)
end
def redirect_proc
Proc.new do |env|
# Use the key 'action_dispatch.request.flash_hash' to set
# an new FlashHash object. This will overrite any existing FlashHash
# object, so use it carefully. You can probably avoid that by checking
# for an existing one and adding to it.
env[FLASH::KEY] = FLASH::FlashHash.new(alert: "Insufficient permissions")
# Construct the redirect response
res = Rack::Response.new
res.redirect("/")
res.finish
end
end
end