How to Log Which Line Initiated a Query in Rails

Create a file (something like) config/initializers/active_record_log_subscriber.rb

…and paste this into its contents:

module LogQuerySource
  def debug(*args, &block)
    return unless super

    backtrace = Rails.backtrace_cleaner.clean caller

    relevant_caller_line = backtrace.detect do |caller_line|

    if relevant_caller_line
      logger.debug("  ↳ #{ relevant_caller_line.sub("#{ Rails.root }/", '') }")
ActiveRecord::LogSubscriber.send :prepend, LogQuerySource

Now, whenever a line of code initiates a SQL query the line will be logged.  This greatly improves the ease of tracking down inefficiencies such as like N + 1 queries.

If you would like to learn more about exactly how this mix-in works and how the original author went about figuring out how to add it, you can read more about it here.


Commenting and Documentation in Ruby and Rails

It’s always been frustrating to me that Ruby and Rails don’t really have strong templated standards on how to best document your code. There are several options available and it can all be very confusing and unclear.

There is one template I’ve found works best and its super simple:

# Brief explanation of what the code does.
# * *Args* :
# - ++ ->
# * *Returns* :
# -
# * *Raises* :
# - ++ ->
def my_method


While there are many other perfectly good documentation libraries this has the benefits of being simple to remember, very easy to read in code, and compiles out super nicely using

rake doc:app

Example (strongly based off this post):

# This is an example method commented the way I 
# like. It sums the three arguments and returns 
# that value.
# Lorem ipsum dolor sit amet, consectetur adipising,
# do eiusmod tempor incididunt ut labore et dolore. 
# Ut enim ad minim veniam, quis nostrud exercit
# laboris nisi ut aliquip ex ea commodo consequat.
# * *Args* :
#   - +apples+ -> the number of apples
#   - +oranges+ -> the number of oranges
#   - +pears+ -> the number of pears
# * *Returns* :
#   - the total number of fruit as an integer
# * *Raises* :
#   - +ArgumentError+ -> if any value is nil or negative
def sum_fruit(apples, oranges, pears)

Will render into something like this:

Other than this, I tend to try and follow the general conventions as outlined by the Rails contribution guidelines on commenting.

NotImplementedError Must Have Battered Wife Syndrome

I’ve been doing something very wrong my whole life.  I think it’s time to confess and seek help.

You see, like so many developers I see the NotImplementedError class in various languages and think, to my self “I haven’t had a chance to fully implement this class, so in my methods that my colleagues call that I didn’t finish yet, I will raise that exception to let them know.”

I am ashamed of myself.  And it’s time to get help.

You see the actual purpose of the NotImplementedError (as defined by the Ruby docs) is:

Raised when a feature is not implemented on the current platform. For example, methods depending on the fsync or fork system calls may raise this exception if the underlying operating system or Ruby runtime does not support them.

ERMERGERD!  I am a terrible person. Abusing this error class just because  my sub classes cannot meet the contractual obligation of the super class.

And I know I am not alone.

So whats the best practice, then?

Well, in Ruby’s case it turns out the answer is super simple; don’t raise an error at all! Instead, document the expectation and if a subclass fails to meet it a NameError, or often its subclass NoMethodError, will be raised automatically.


How to manually mark ActiveRecord attribute as dirty

Recently I had quite a conundrum. I was working on a project’s model that was using the ActiveRecord save method update_columns to avoid executing the callbacks on the model, however had the unexpected side-effect further down my stack when a method in the chain checked if a particular attribute changed, wasn’t working because as well as skipping validations and callbacks; it also bypasses the ActiveModel::Dirty logic!

This caused me quite a problem, as I feared that I would be forced to use a method of saving the record that triggered my callbacks (very undesirable).

Fortunately, there is a solution.  Because the ActiveModel::Dirty class is still loaded, you can manually mark with attributes are dirty by simply calling [attr_name]_will_change! before the change to track the attribute.


Normally this is all done for you and now later on in the stack when you do something like

if attribute_name_changed?
  was = attribute_name_was

It will work, despite using a method to save that doesn’t automatically track the dirty attributes for you.

Actually the ActiveModel::Dirty module has some pretty cool stuff in it. Much of it never gets properly explored in the average Rails project, but it provides some hidden magic, like being able to fully revert an object and undo a save, providing a kind of diff of changes and some other really neat stuff.