CNU CODE

Metal Session

Posted in Ruby on Rails by Srinivas Reddy on July 25, 2009

In my previous post there is a simple metal application, implementation fast metal paste kind of feature.

Metal classes bypass routing and Action Controller to give you raw speed (at the cost of all the things in Action Controller, of course). This builds on all of the recent foundation work to make Rails a Rack application with an exposed middleware stack.

Note: Rails version required is 2.3

For example I was trying to leverage a resource via metal, but the resource shouldn’t be accessed by other and it is locked by current user. So I need to check the session for logged-in user before giving that resource. Can I access session in metal?

Try this in rails application root “rake middleware”, it shows all the middleware stack in current application

srinivas@Azr_CLE9:~/work/metal_app$ 
srinivas@Azr_CLE9:~/work/metal_app$ rake middleware
(in /home/srinivas/work/metal_app)
use Rack::Lock
use ActionController::Failsafe
use ActionController::Reloader
use ActionController::Session::CookieStore, #
use Rails::Rack::Metal
use ActionController::RewindableInput
use ActionController::ParamsParser
use Rack::MethodOverride
use Rack::Head
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
run ActionController::Dispatcher.new
srinivas@Azr_CLE9:~/work/metal_app$
srinivas@Azr_CLE9:~/work/metal_app$ 

Shows that the ActionController::Session::CookieStore is included before Rails::Rack::Metal middleware(in rack stack session middleware takes precedence), so its clear that for metal middleware, session are accessible via rack session store. In the Rack environment that is passed to the call method, the session is stored at the ‘rack.session’ index. You can use this to both read from and write to the session.

Here is the code examples:

class Myresource
   # get the current_user from the rack session and check the user has locked the record
  def initialize(env)
    @session = env["rack.session"]
    @db_connection = ActiveRecord::Base.connection()
    if !@session.nil? && @session[:user_id]
      @current_user = @db_connection.execute(
        "SELECT * FROM users WHERE (users.id = #{@session[:user_id]}) LIMIT 1"
      ).fetch_row # returns logged-in user
    end
  end

  def self.call(env)
    if env["PATH_INFO"] =~ /^\/myresource\/(\w+.pdf)$/
      Myresource.new(env).send_pdf($1)
    else
      [404, {"Content-Type" => "text/html"}, ["Not Found"]]
    end
  ensure
    # Release the connections back to the pool.
    ActiveRecord::Base.clear_active_connections!
  end

  def send_pdf(pdf_name)
    @wip = @db_connection.execute(
      "SELECT uesr_id, is_locked FROM pdf WHERE
       pdf_file = pdf_name LIMIT 1"
    ).fetch_row # returns [user_id, is_loked]
    unless @session.nil? || @current_user.nil?
      if @pdf.nil? || ( @pdf[0].to_i != @session[:user_id] && @pdf[1].to_i == 0 )
        [200, {"Content-Type" => "text/html"}, "Permission Denied"]
      else
        [200, {"Content-Type" => "application/pdf"}, File.read( MESSAGES_ROOT + pdf_name )]
      end
    else
      [302, {'Location'=> '/login' }, []]
    end
  end
end

Thanks
Srinivas Reddy

Advertisements