使用Flash消息功能构建机架中间件响应

时间:2015-10-05 17:58:44

标签: ruby-on-rails sinatra rack rack-middleware

我有一个Sinatra应用程序,它安装在/admin下的Rails应用程序中。 Sinatra应用程序是一个管理仪表板,因此只应供授权用户使用。

为了强制执行,我构建了一个Rack Sinware,它将在调用Sinatra应用程序之前运行。

逻辑很简单 -

  1. 如果用户已通过身份验证,请继续正常
  2. 如果用户未经过身份验证,请使用闪存警报消息重定向到根路径(我正在使用rack-flash gem来允许访问Rack中的Flash消息)
  3. 以下代码。我觉得我在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
    

1 个答案:

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