Rails

Writing Clean Monkey Patches

Posted by Weston Ganger on January 17, 2017

I recently did bundle update on a project. I later noticed that the pagination was giving me an error:


ArgumentError - comparison of Fixnum with String failed.

This turned out to be a bug in Kaminari v1.0.0. I figure this probably caught quite a few people off guard considering this is the most popular pagination library. This Kaminari error was fixed in master but they hadn’t released v1.0.1 yet. I didn’t want to downgrade to a pre v1.0.0 version so I developed the following monkey patch to solve the issue until v1.0.1 was released.


My monkey patch had to meet the following criteria:

  • If I happen to forget to remove the monkey patch, it needs to disable itself when I upgrade. I ended up having to require the kaminari/version file to be able to access the Kaminari::VERSION constant.
  • I only want to enhance the code that I am patching, I do not want to overwrite it. In my opinion a clean monkey patch should do work before or after the original implementation is called, however sometimes reality isn’t so simple. I recently learned about this prepend method and basically it allows you to call super in your monkey patch to call the original method in its exact form which is pretty slick.


With that in mind here is the monkey patch in all its glory.


# config/initializers/kaminari_monkey_patch.rb

require 'kaminari/version'

if Kaminari::VERSION == "1.0.0"

  Kaminari::PageScopeMethods.module_eval do
    prepend(KaminariFix = Module.new do    
 
      def per(num, max_per_page: nil)
        if num && num.is_a?(String)
          num = num.to_i 
        end

        super # or you can do `super(num, max_per_page: max_per_page)` which is the same thing
      end

    end)
  end

else
  Rails.logger.debug("WARNING: You are running Kaminari #{Kaminari::VERSION}. The monkey patch located at config/initializers/kaminari_monkey_patch.rb only applies to 1.0.0, so please remove the monkey patch if you are seeing this message.")
  ### or maybe you might rather raise an error instead, its totally up to you
end

This fixed the problem splendidly.

I hope this encourages you to monkey patch more often, it can help solve large issues with ease. I also hope it makes you love Ruby just a little more.


Note 1: Yes, the parenthesis ( ) for the prepend call are required when using this inline style. If you do not use the parenthesis it will fail silently and the patch will not be applied.

Note 2: If your having a hard time understanding the monkey patch then I recommend you read the following article: https://bibwild.wordpress.com/2016/12/27/a-class_eval-monkey-patching-pattern-with-prepend/


Related External Links:


Posted in Rails and Tagged with ruby kaminari rails monkey-patch 


Need help on your next project or application?

I specialize in Ruby-on-Rails, AngularJS, Javascript, Bootstrap, and Hybrid Mobile Apps with Cordova & Ionic.

Contact Me

Recommended Posts