Err the Blog Atom Feed Icon
Err the Blog
Rubyisms and Railities
  • “Auto-Patch Rails”
    – PJ on July 27, 2006

    Want to use a patch from the Rails’ Trac that DHH didn’t think was a good fit? Patching some core functionality of Rails that you don’t want to make into a plugin?

    Place the following code in config/environment.rb before boot.rb is required.
    require File.join(File.dirname(__FILE__), '../lib/rails_patcher')
    Rails::Patcher.run
    
    And this into lib/rails_patcher.rb
    module Rails
      module Patcher
        ROOT_DIR = File.join(File.dirname(__FILE__), '..')
        PATCHES_DIR = "#{ROOT_DIR}/lib/patches/"
    
        def self.run
          `mkdir #{PATCHES_DIR}` unless File.directory?(PATCHES_DIR)
          `rake rails:freeze:gems` unless File.directory?("#{ROOT_DIR}/vendor/rails")
    
          Dir["#{PATCHES_DIR}/*"].each do |file|
            next if %w(. ..).include?(file) || file =~ /^APPLIED_/
            STDERR.print "Patching #{file}..."
            `patch -d #{ROOT_DIR}/vendor/rails -p0 < #{PATCHES_DIR}/#{file}`
            STDERR.print "Done.\n"
            `mv #{PATCHES_DIR}/#{file} #{PATCHES_DIR}/APPLIED_#{file}`
          end
        end
      end
    end
    

    All that is left is for you is to drop your diff’s into lib/patches, start your server, and the patches are automatically applied once to vendor/rails

    The only caveat is that this won’t work if you’re on Windows. Other than that, the code is fairly straightforward if you have any questions about what’s going on.

    Update: using the right rake task to freeze the rails gems now.

  • Stephen Bannasch, 9 months later:

    Thanks for the idea. To get it to work I had to add the following in the inner loop.

     file = File.basename(file)

    So the whole inner loop now looks like this:

          Dir["#{PATCHES_DIR}/*"].each do |file|
            file = File.basename(file)
            next if %w(. ..).include?(file) || file =~ /^APPLIED_/
            STDERR.print "Patching #{file}..."
            `patch -d #{ROOT_DIR}/vendor/rails -p0 < #{PATCHES_DIR}/#{file}`
            STDERR.print "Done.\n"
            `mv #{PATCHES_DIR}/#{file} #{PATCHES_DIR}/APPLIED_#{file}`
          end
    

    With file set to the complete path it didn’t work.

  • One person has commented.
    Chime in.
    Sorry, no more comments :(
This is Err, the weblog of PJ Hyett and Chris Wanstrath.
All original content copyright ©2006-2008 the aforementioned.