Search code examples
ruby-on-railsrubydirectorymonkeypatching

Should I use the `lib` folder or the `initializers` folder for Rails monkey patches?


I have a few functions that monkey patch the string class in a file named string_class.rb which is currently placed in the config\initializers\string_class.rb. The code looks like this:

class String

  def capitalize_first_char
    self.sub(/^(.)/) { $1.capitalize }
  end

  def capitalize_each_sentence
    self.gsub(/([a-z])((?:[^.?!]|\.(?=[a-z]))*)/i) { $1.upcase + $2.rstrip }
  end

end

After doing quite a bit of research I am on the fence if this class should live in the initializers or the lib folder.


Solution

  • There isn't a good place for this sort of thing to live in a Rails application, because it's not the sort of thing you should be doing through the normal course of building a Rails app. Patching core classes is expressly advised against in pretty much every style-guide going.

    • config/initializers is probably the wrong place to do this. Typically this is for setting up dependencies for your app, and most people won't think to look there for code mixing strange methods into core classes
    • lib is probably a better place, but it's not auto-reloaded by default
    • Gemfile? If this is worth patching into String, it might be worth distilling into a Gem and thoroughly documenting.

    I would personally sidestep the problem and simply introduce helper methods. You can make the helper methods available across all controllers by defining them in app/controllers/application_controller.rb. You can then make the methods available to your views with the helper_method function:

    class ApplicationController < ActionController::Base
    
      helper_method :capitalize_first_char, :capitalize_each_sentence
    
      #...
    
      protected
    
      def capitalize_first_char(str)
        str.sub(/^(.)/) { $1.capitalize }
      end
    
      def capitalize_each_sentence(str)
        str.gsub(/([a-z])((?:[^.?!]|\.(?=[a-z]))*)/i) { $1.upcase + $2.rstrip }
      end
    end