Make Rails' Auto-linker Accept Parentheses

The Rails helper, auto_link is a handy way to scan a block of text, adding HTML links as they are found. I recognized an issue with its regular expression, however, when dealing with files commonly linked to on my last project.

The links in question look like this:

http://www.website.com/assets/screenshotbundle(5-20-08).zip
Unfortunately, Rails was creating links that looked something like this:
http://www.website.com/assets/screenshotbundle(5-20-08).zip
While parentheses aren't necessarily commonplace in URLs, they're still acceptable; Web browsers won't balk when they're encountered. It's clear that we need to patch our helper to accept parentheses.

Delving into the auto_link method in ActionView::Helpers::TextHelper, it's working off a rather large regular expression defined as the constant, AUTO_LINK_RE. To safely change this constant, you need to do so within the initializer block in environment.rb. If you try to define it by putting a file in the config/initializers directory, you'll get a warning that the constant has already been defined. Here's my updated definition:

Rails::Initializer.run do |config|
  module ActionView
    module Helpers
      module TextHelper
        AUTO_LINK_RE = %r{
          (                          # leading text
            <\w+.*?>|                # leading HTML tag, or
            [^=!:'"/]|               # leading punctuation, or
            |                        # nothing
          )
          (
            (?:https?://)|           # protocol spec, or
            (?:www\.)                # www.*
          )
          (
            [-\w]+                   # subdomain or domain
            (?:\.[-\w]+)*            # remaining subdomains or domain
            (?::\d+)?                # port
            (?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:][^\s$]))+)?)* # path
            (?:\?[\w\+@%&=.;-]+)?    # query string
            (?:\#[\w\-]*)?           # trailing anchor
          )
          ([[:punct:]]|\s|<|$)       # trailing text
        }x
      end
    end
  end
end

Update: I've created a ticket to correct this behavior.

Leave a Reply