Writing Monkey Patches in Ruby

Introduction:

Ruby is known for its flexibility and openness, allowing developers to customize and extend the language’s core functionality. One powerful way to do this is by using monkey patches. Monkey patching enables you to modify or add new behavior to existing Ruby classes or modules without changing their original source code. In this blog, we’ll explore the concept of monkey patching in Ruby, how it works, and when to use it responsibly.

What is Monkey Patching?

Monkey patching is a technique in Ruby that lets you modify or enhance the behavior of classes, modules, or objects at runtime. It’s called “monkey patching” because it’s like a monkey altering the behavior of a class in an unpredictable way. Ruby’s open classes and dynamic nature make this possible.

The Motivation

From last few months we are facing an error which have become hard to replicate in development environment. The error is

ActiveRecord::StatementInvalid

ActiveRecord::JDBCError: org.postgresql.util.PSQLException: ERROR: missing FROM-clause entry for

This error occurs rarely and replicating have become hard. The idea was to log the query and see why the query is forming correctly.

Then I used, query.to_sql to log the query but this raise a new error

Arel::Visitors::UnsupportedVisitError

Unsupported argument type: NilClass. Construct an Arel node instead.

Now, i’m not even able to log the query directly, because to get query I have to use to_sql function which have some internal validation that throws an exception if the query is Invalid.

Solution:

One of the feature that rails provide is monkey patch. Which allow us to override library functions and enable us to provide custom logic for these library function. I monkey patched StatementInvalid class to print the sql directly without validation.

module ActiveRecord
  class StatementInvalid < ActiveRecordError
    def initialize(message = nil, sql: nil, binds: nil)
      Sentry.capture_message("Invalid SQL Statement", :extra => { query: sql }) if Sentry.present? && sql.present?
      super(message || $!&.message)
      @sql = sql
      @binds = binds
    end

    attr_reader :sql, :binds
  end
end

This logs the sql which will enable us to find the root cause of wrong statement generation

Conclusion:

Monkey patching is a powerful technique in Ruby that empowers developers to extend and modify core classes and modules. While it offers great flexibility, it should be used with care and responsibility. Proper documentation, versioning, and testing are essential to ensure your monkey patches integrate seamlessly with your projects and avoid potential conflicts. With a clear understanding of when and how to use monkey patching, you can harness its potential to make your Ruby code more expressive and efficient. Happy coding!

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *