Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - how can I make a request that doesn't hit the database at all?

In order to trace some performance issues, I'm trying to create a page that is rendered through the Rails (2.3.8) framework but makes no calls whatsoever to the database.

I want the request to go through the typical middleware (routes.rb > controller > view), as opposed to rendering a simple static page (like 404.html), and in it should work when the db server is turned off (web server still running). The actual rendered page is a simple html page displaying the currency time using erb. Right now I get error when I turn off the database, and I can see 2 queries that are still made:

SQL (0.1ms)   SET NAMES 'utf8'
SQL (0.1ms)   SET SQL_AUTO_IS_NULL=0

Any idea how to override the db completely while making that request? thanks.

like image 489
sa125 Avatar asked Feb 08 '11 06:02

sa125


1 Answers

The only way to get around it is to override the configure_connection function in ActiveRecord. To do this I would recommend making an ApplicationController function named skip_sql? to test whether you want to skip the configure_connection function for some controller#action combinations:

class ApplicationController
  def skip_sql?
    params[:controller] == "..." && params[:action] == "..."
  end
end

Then make this function available to your classes and models:

module SkipSql
  module Controller
    def self.included(base)
      base.prepend_before_filter :assign_skip_sql_to_models
    end

    def assign_skip_sql_to_models
      ActiveRecord::Base.skip_sql_proc = proc {send(:skip_sql?)}
    end
  end
  module Model
    def self.included(base)
      base.extend ClassMethods
    end

    module ClassMethods
      attr_accessor :skip_sql_proc

      def skip_sql?
        ActiveRecord::Base.skip_sql_proc.call if ActiveRecord::Base.skip_sql_proc
      end

    end

    def skip_sql?
      self.class.skip_sql?
    end
  end
end

Object.send :include, SkipSql::Model::ClassMethods
ActionController::Base.class_eval {include SkipSql::Controller}

Then skip sql only on the controller#action combinations you have set:

class ActiveRecord::ConnectionAdapters::MysqlAdapter
  def configure_connection
    unless skip_sql?
      encoding = @config[:encoding]
      execute("SET NAMES '#{encoding}'", :skip_logging) if encoding

      execute("SET SQL_AUTO_IS_NULL=0", :skip_logging)
    end
  end
end

If the configure_connection one doesn't work I would try the connect method like this:

class ActiveRecord::ConnectionAdapters::MysqlAdapter
  alias :old_connect :connect

  def connect
    old_connect unless skip_sql?
  end

  alias :old_active? :active?

  def active?
    skip_sql? ? false : old_active?
  end
end

I believe the connect method gets called before the configure connection method, so it should help with the socket issue.

like image 89
Pan Thomakos Avatar answered Sep 19 '22 02:09

Pan Thomakos