I have a Sinatra app that's mounted on a Rails app under /admin
. The Sinatra app is an admin dashboard, and therefore should only be available to authorized users.
To enforce that, I built a piece of Rack Middleware that will run before the Sinatra app is called.
The logic is simple -
- If user is authenticated, continue as normal
- If user is not authenticated, redirect to the root path with a flash alert message (I'm using the rack-flash gem to allow access to the flash messages in Rack)
Code below. I feel like I'm missing something in the redirect
method. The Rack::Builder
block constructs a mini-Rack application and the block inside further creates another Rack application (the Proc) that builds the Redirect Response with flash message.
When I run it, I get undefined method 'detect' for nil:NilClass
, which indicates that neither block is returning a valid non-nil
response. Do I need to run call
somewhere on one of these blocks?
I'm using a Puma Webserver if that helps.
Thanks!
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
Ok, figured it out myself for anyone else that's curious.
I had to use the
env
key'action_dispatch.request.flash_hash'
, which is used by the Flash middelware hereI didn't have to use the
rack-flash
gem, although I'm sure that's still useful when building Sinatra apps and suchNOTE: This is on Rails v4.2.4. I believe there have been several changes to that
Flash
module since, so I don't know if that key has changed. But you can confirm by searching the latest repo for a similar definition.