FIX: Compatibility with peek-mysql2 on Rails ≥ 5 (#451)

FIX: Compatibility with peek-mysql2 on Rails ≥ 5 (#451)

See compatibility with peek-mysql2 by glaszig · Pull Request #451 · MiniProfiler/rack-mini-profiler · GitHub for details.

diff --git a/README.md b/README.md
index 23945cb..61b93b2 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,16 @@ gem 'rack-mini-profiler', require: ['prepend_net_http_patch']
 
 This conflict happens when a ruby method is patched twice, once using module prepend, and once using method aliasing. See this [ruby issue](https://bugs.ruby-lang.org/issues/11120) for details. The fix is to apply all patches the same way. Mini Profiler by default will apply its patch using method aliasing, but you can change that to module prepend by adding `require: ['prepend_net_http_patch']` to the gem line as shown above.
 
+#### `peek-mysql2` stack level too deep errors
+
+If you use peek-mysql2 with Rails >= 5, you'll need to use this gem spec in your Gemfile:
+
+`‍``ruby
+gem 'rack-mini-profiler', require: ['prepend_mysql2_patch', 'rack-mini-profiler']
+`‍``
+
+This should not be necessary with Rails < 5 because peek-mysql2 hooks into mysql2 gem in different ways depending on your Rails version.
+
 #### Rails and manual initialization
 
 In case you need to make sure rack_mini_profiler is initialized after all other gems, or you want to execute some code before rack_mini_profiler required:
diff --git a/lib/patches/db/mysql2.rb b/lib/patches/db/mysql2.rb
index 576ae4b..26c2a6a 100644
--- a/lib/patches/db/mysql2.rb
+++ b/lib/patches/db/mysql2.rb
@@ -1,30 +1,7 @@
 # frozen_string_literal: true
 
-# The best kind of instrumentation is in the actual db provider, however we don't want to double instrument
-
-class Mysql2::Result
-  alias_method :each_without_profiling, :each
-  def each(*args, &blk)
-    return each_without_profiling(*args, &blk) unless defined?(@miniprofiler_sql_id)
-
-    start        = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-    result       = each_without_profiling(*args, &blk)
-    elapsed_time = SqlPatches.elapsed_time(start)
-
-    @miniprofiler_sql_id.report_reader_duration(elapsed_time)
-    result
-  end
-end
-
-class Mysql2::Client
-  alias_method :query_without_profiling, :query
-  def query(*args, &blk)
-    return query_without_profiling(*args, &blk) unless SqlPatches.should_measure?
-
-    result, record = SqlPatches.record_sql(args[0]) do
-      query_without_profiling(*args, &blk)
-    end
-    result.instance_variable_set("@miniprofiler_sql_id", record) if result
-    result
-  end
+if defined?(Rack::MINI_PROFILER_PREPEND_MYSQL2_PATCH)
+  require "patches/db/mysql2/prepend"
+else
+  require "patches/db/mysql2/alias_method"
 end
diff --git a/lib/patches/db/mysql2/alias_method.rb b/lib/patches/db/mysql2/alias_method.rb
new file mode 100644
index 0000000..576ae4b
--- /dev/null
+++ b/lib/patches/db/mysql2/alias_method.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+# The best kind of instrumentation is in the actual db provider, however we don't want to double instrument
+
+class Mysql2::Result
+  alias_method :each_without_profiling, :each
+  def each(*args, &blk)
+    return each_without_profiling(*args, &blk) unless defined?(@miniprofiler_sql_id)
+
+    start        = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+    result       = each_without_profiling(*args, &blk)
+    elapsed_time = SqlPatches.elapsed_time(start)
+
+    @miniprofiler_sql_id.report_reader_duration(elapsed_time)
+    result
+  end
+end
+
+class Mysql2::Client
+  alias_method :query_without_profiling, :query
+  def query(*args, &blk)
+    return query_without_profiling(*args, &blk) unless SqlPatches.should_measure?
+
+    result, record = SqlPatches.record_sql(args[0]) do
+      query_without_profiling(*args, &blk)
+    end
+    result.instance_variable_set("@miniprofiler_sql_id", record) if result
+    result
+  end
+end
diff --git a/lib/patches/db/mysql2/prepend.rb b/lib/patches/db/mysql2/prepend.rb
new file mode 100644
index 0000000..fd00a82
--- /dev/null
+++ b/lib/patches/db/mysql2/prepend.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+class Mysql2::Result
+  module MiniProfiler
+    def each(*args, &blk)
+      return super unless defined?(@miniprofiler_sql_id)
+
+      start        = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+      result       = super
+      elapsed_time = SqlPatches.elapsed_time(start)
+
+      @miniprofiler_sql_id.report_reader_duration(elapsed_time)
+      result
+    end
+  end
+
+  prepend MiniProfiler
+end
+
+class Mysql2::Client
+  module MiniProfiler
+    def query(*args, &blk)
+      return super unless SqlPatches.should_measure?
+
+      result, record = SqlPatches.record_sql(args[0]) do
+        super
+      end
+      result.instance_variable_set("@miniprofiler_sql_id", record) if result
+      result
+    end
+  end
+
+  prepend MiniProfiler
+end
diff --git a/lib/prepend_mysql2_patch.rb b/lib/prepend_mysql2_patch.rb
new file mode 100644
index 0000000..67e53a1
--- /dev/null
+++ b/lib/prepend_mysql2_patch.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+module Rack
+  MINI_PROFILER_PREPEND_MYSQL2_PATCH = true
+end

GitHub sha: 396b2a1e

This commit appears in #451 which was merged by OsamaSayegh.