2

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
1

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Hi, actually I'm getting an error include ActiveModel::Validations validates_with MyValidator. Do I need to include the files somehow? I have them in app/validators/ folder? I didn't see any mention of this in the guide
You don't need to include anything. Just create app/validators/image_url_validator.rb as described and add this line to SearchResult model: validates :thumbnail, image_url: true, allow_blank: true.
In the guide EmailValidator describes this instead of MyValidator: guides.rubyonrails.org/…
1

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

Comments

-1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.