Recently we encountered a bug where a link in a delivered email was not working. A quick investigation revealed that the problem was due to a relative url being generated instead of absolute. The problem was easy to fix but we wanted to put a safeguard in place to prevent this from happening in the future.
As far as I know, Rails provides 3 different helper methods to generate urls:
url_for
helperlink_to
helper which delegates tourl_for
- Named route helpers such as
product_path(@product)
which delegate tourl_for
Therefore it seems like as long as we override the implementation of url_for
in our mailers and throw an
exception when the provided url is relative, we can prevent the mailer from being delivered:
# config/initializers/mailer_link_validator.rb
ActionMailer::Base.helper do
def url_for(options = nil)
url = super(options)
return url if absolute_url?(url) || fragment?(url)
fail 'Can not provide relative urls in mailers'
end
private
def absolute_url?(url)
URI.parse(url).is_a? URI::HTTP
rescue
false
end
def fragment?(url)
url.start_with? '#'
end
end