0

In my model I have added the following code for validation of a URL a user can enter:

validates :website, presence: true
validates :website, format: { with: URI.regexp }, if: 'website.present?'

I have written a test with the an invalid url:

http://example,nl

When I run the test, the validation says this is a valid input. I have tried it in the program it self and this is an accepted URI. Is there a way to set the URI.regex so this is an invalid URL?

PieterB
  • 140
  • 1
  • 12

1 Answers1

1

URI.regexp returns a URI which will match all valid URIs, but a) it doesn't validate that the string is only that URI, and b) you want to validate URLs, not URIs (URI is the broader term).

For a), you can modify the regex to match only if the string is just the URI by wrapping it in the ^ (start-of-line) and $ (end-of-line) symbols:

validates :website, format: { with: /^#{URI.regexp.to_s}$/ }, if: 'website.present?'

For b), you could change your call to URI.regexp(['http', 'https']) to limit the allowed schemes, which gets you closer. There are also gems for this problem, like valid_url. Or, just accept that your validation will never be perfect.

Robert Nubel
  • 7,104
  • 1
  • 18
  • 30
  • Thanks Robert, I have added the following Regex which works: /\A(?:(?:https?|http):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?\z/i – PieterB Jun 30 '16 at 09:50