Reputation: 6383
I've got a model that refers to a table with a thumbnail column. As for validation, I want the thumbnail to accept values of either empty/nil or a valid url (ideally jpg/gif). Below is my attempt but it doesn't seem to be validating as expected. Could someone please have a look at my model below and tell me where I'm going wrong, thanks
class SearchResult < ActiveRecord::Base
validate :check_thumbnail
private
def check_thumbnail
if self.thumbnail.nil?
true
else
if /https?:\/\/[\S]+/.match(self.thumbnail).nil?
false
else
false
end
end
end
end
Upvotes: 1
Views: 641
Reputation: 2403
Using official guide for custom validations I would recommend to create url_validator.rb
in your app/validators
with the following content:
class UrlValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << (options[:message] || 'must be a valid URL') unless url_valid?(value)
end
def url_valid?(url)
uri = URI.parse(url) rescue false
uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
end
end
Thereafter you may validate thumbnail
attribute like this:
class SearchResult < ActiveRecord::Base
validates :thumbnail, url: true, allow_blank: true
end
Also you may improve url_valid?
method to consider extension whitelist via regex (however I would create another validator for this, e.g. image_url_validator.rb
to keep basic url validator).
EDIT:
app/validators/image_url_validator.rb
class ImageUrlValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << (options[:message] || 'must be a valid URL (only jpg and gif)') unless url_valid?(value)
end
def url_valid?(url)
uri = URI.parse(url) rescue false
(uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)) && uri.to_s.match(/\.jpg|\.gif/)
end
end
app/models/search_result.rb
class SearchResult < ActiveRecord::Base
validates :thumbnail, image_url: true, allow_blank: true
end
Key benefit of this approach is that you may reuse this custom validations for different attributes in different models.
Upvotes: 2
Reputation: 32933
I would rewrite it as
class SearchResult < ActiveRecord::Base
validate :check_thumbnail
private
def check_thumbnail
unless self.thumbnail.blank? || self.thumbnail =~ /https?:\/\/[\S]+/
self.errors.add(:thumbnail, "is not valid")
end
end
end
Upvotes: 1
Reputation: 17834
Use this regex to validate URL, I've used this myself
/\A(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix
here in your code in the else block, do this way
else
URL_REGEX = /\A(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix
if (URL_REGEX).match(self.thumbnail).nil?
false
else
false
end
end
Upvotes: -1