Ryan
Ryan

Reputation: 6642

Best Practice -- Validating URL Rails3

What is the best way to validate a URL in an ActiveRecord?

I have thought about applying these requirements:

  1. Should be a publicly routable URL, i.e., should NOT be on localhost, 127.0.0.1
  2. Should be HTTP status code 2xx, 3xx (follow 3xx to 2xx, if more than 10 redirects then fail)

My trepidation comes from the 2nd requirement. The code will have to verify the address, thus taking time and could make the submit form take a long time to validate. Is this requirement reasonable?

Comments and suggestions are welcome.

Upvotes: 1

Views: 533

Answers (1)

Unixmonkey
Unixmonkey

Reputation: 18784

Send it to a job queue like Delayed Job to be done outside the request/response cycle, so you can accept the data now and not hold up the user, and after processing, either save the record (if valid), or discard if invalid.

Of course, if you have to discard it, you might want to fire off something else that lets the user know there was a problem. Since it is outside the request, you'll either have to get the user's attention on later pages (flash message maybe?) or send them an email.

edit: to further illustrate:

I would create a column called unverified_url as well as url, then set the form to submit to unverified_url

require 'net/http'
require 'uri'

after_save :verify_url_later

def verify_url_later
  self.delay.verify_url
end

def verify_url
  if !unverified_url.match(/127.0.0.1|localhost/) && fetch(unverified_url)
    # all good, save to publicly-accessible url
    self.update_attributes(:url => unverified_url, :unverified_url => nil)
  else
    UserMailer.bad_url_notification(unverified_url).deliver
  end
end

def fetch(uri_str, limit = 10)
  response = Net::HTTP.get_response(URI.parse(uri_str))
  case response
    when Net::HTTPSuccess
      response
    when Net::HTTPRedirection
      fetch(response['location'], limit - 1) unless limit == 0
  else
    response.error!
  end
end

Upvotes: 1

Related Questions