[ruby-on-rails] Rails : 링크 (URL)의 유효성을 검사하는 좋은 방법은 무엇입니까?

Rails에서 URL을 가장 잘 검증하는 방법이 궁금합니다. 정규 표현식을 사용하려고 생각했지만 이것이 최선의 방법인지 확실하지 않습니다.

그리고 내가 정규식을 사용한다면 누군가 나에게 하나를 제안 할 수 있습니까? 나는 여전히 Regex를 처음 사용합니다.



답변

URL 유효성 검사는 까다로운 작업입니다. 또한 매우 광범위한 요청입니다.

정확히 무엇을 하시겠습니까? URL 형식, 존재 여부 또는 무엇을 확인 하시겠습니까? 수행하려는 작업에 따라 몇 가지 가능성이 있습니다.

정규식은 URL 형식의 유효성을 검사 할 수 있습니다. 그러나 복잡한 정규식조차도 유효한 URL을 처리하고 있는지 확인할 수 없습니다.

예를 들어 간단한 정규 표현식을 사용하면 다음 호스트를 거부 할 것입니다.

http://invalid##host.com

그러나 그것은 허용 할 것입니다

http://invalid-host.foo

유효한 호스트이지만 기존 TLD를 고려할 경우 유효한 도메인이 아닙니다. 실제로 다음 항목이 유효한 호스트 이름이므로 도메인이 아닌 호스트 이름을 확인하려는 경우 솔루션이 작동합니다.

http://host.foo

다음 중 하나

http://localhost

이제 몇 가지 해결책을 드리겠습니다.

도메인의 유효성을 검사하려면 정규식을 잊어야합니다. 현재 사용 가능한 최상의 솔루션은 Mozilla에서 관리하는 목록 인 Public Suffix List입니다. Public Suffix List에 대해 도메인을 구문 분석하고 유효성을 검사하기 위해 Ruby 라이브러리를 만들었으며 PublicSuffix 라고합니다. 합니다.

URI / URL의 형식을 검증하려면 정규식을 사용할 수 있습니다. 하나를 검색하는 대신 내장 Ruby URI.parse메서드를 사용하십시오 .

require 'uri'

def valid_url?(uri)
  uri = URI.parse(uri) && !uri.host.nil?
rescue URI::InvalidURIError
  false
end

더 제한적으로 만들 수도 있습니다. 예를 들어 URL이 HTTP / HTTPS URL이되도록하려면 유효성 검사를 더 정확하게 만들 수 있습니다.

require 'uri'

def valid_url?(url)
  uri = URI.parse(url)
  uri.is_a?(URI::HTTP) && !uri.host.nil?
rescue URI::InvalidURIError
  false
end

물론 경로 또는 구성표 확인을 포함하여이 방법에 적용 할 수있는 많은 개선 사항이 있습니다.

마지막으로이 코드를 유효성 검사기로 패키징 할 수도 있습니다.

class HttpUrlValidator < ActiveModel::EachValidator

  def self.compliant?(value)
    uri = URI.parse(value)
    uri.is_a?(URI::HTTP) && !uri.host.nil?
  rescue URI::InvalidURIError
    false
  end

  def validate_each(record, attribute, value)
    unless value.present? && self.class.compliant?(value)
      record.errors.add(attribute, "is not a valid HTTP URL")
    end
  end

end

# in the model
validates :example_attribute, http_url: true


답변

내 모델 내부에 하나의 라이너를 사용합니다.

validates :url, format: URI::regexp(%w[http https])

충분히 좋고 사용하기 쉽다고 생각합니다. 또한 내부적으로 동일한 정규 표현식을 사용하므로 이론적으로 Simone의 방법과 동일해야합니다.


답변

Simone의 아이디어에 따라 자신 만의 유효성 검사기를 쉽게 만들 수 있습니다.

class UrlValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    return if value.blank?
    begin
      uri = URI.parse(value)
      resp = uri.kind_of?(URI::HTTP)
    rescue URI::InvalidURIError
      resp = false
    end
    unless resp == true
      record.errors[attribute] << (options[:message] || "is not an url")
    end
  end
end

그런 다음

validates :url, :presence => true, :url => true

모델에서.


답변

도 있습니다 validate_url 보석 단지 멋진 래퍼 (Addressable::URI.parse 솔루션).

그냥 추가

gem 'validate_url'

에 추가 Gemfile한 다음 모델에서

validates :click_through_url, url: true


답변

이 질문은 이미 답변되어 있지만 도대체 내가 사용하는 솔루션을 제안합니다.

정규식은 내가 만난 모든 URL에서 잘 작동합니다. setter 방법은 프로토콜이 언급되지 않은 경우 처리하는 것입니다 (http : //로 가정).

마지막으로 페이지를 가져 오려고합니다. HTTP 200 OK뿐만 아니라 리디렉션을 수락해야 할 수도 있습니다.

# app/models/my_model.rb
validates :website, :allow_blank => true, :uri => { :format => /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)/ix }

def website= url_str
  unless url_str.blank?
    unless url_str.split(':')[0] == 'http' || url_str.split(':')[0] == 'https'
        url_str = "http://" + url_str
    end
  end
  write_attribute :website, url_str
end

과…

# app/validators/uri_vaidator.rb
require 'net/http'

# Thanks Ilya! http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/
# Original credits: http://blog.inquirylabs.com/2006/04/13/simple-uri-validation/
# HTTP Codes: http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTPResponse.html

class UriValidator < ActiveModel::EachValidator
  def validate_each(object, attribute, value)
    raise(ArgumentError, "A regular expression must be supplied as the :format option of the options hash") unless options[:format].nil? or options[:format].is_a?(Regexp)
    configuration = { :message => I18n.t('errors.events.invalid_url'), :format => URI::regexp(%w(http https)) }
    configuration.update(options)

    if value =~ configuration[:format]
      begin # check header response
        case Net::HTTP.get_response(URI.parse(value))
          when Net::HTTPSuccess then true
          else object.errors.add(attribute, configuration[:message]) and false
        end
      rescue # Recover on DNS failures..
        object.errors.add(attribute, configuration[:message]) and false
      end
    else
      object.errors.add(attribute, configuration[:message]) and false
    end
  end
end


답변

valid_url 을 사용해 볼 수도 있습니다.스키마없이 URL을 허용하고 도메인 영역과 ip-hostnames를 확인하는 gem을 .

Gemfile에 추가하십시오.

gem 'valid_url'

그리고 모델에서 :

class WebSite < ActiveRecord::Base
  validates :url, :url => true
end


답변

내 2 센트 :

before_validation :format_website
validate :website_validator

private

def format_website
  self.website = "http://#{self.website}" unless self.website[/^https?/]
end

def website_validator
  errors[:website] << I18n.t("activerecord.errors.messages.invalid") unless website_valid?
end

def website_valid?
  !!website.match(/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-=\?]*)*\/?$/)
end

편집 : 매개 변수 URL과 일치하도록 정규식을 변경했습니다.