Rails : 링크 (URL)를 확인하는 좋은 방법은 무엇입니까?
Rails에서 URL을 가장 잘 검증하는 방법이 궁금합니다. 정규 표현식을 사용하려고 생각했지만 이것이 최선의 방법인지 확실하지 않습니다.
그리고 정규식을 사용한다면 누군가 나에게 제안 할 수 있습니까? 나는 여전히 정규식을 처음 사용합니다.
URL 확인은 까다로운 작업입니다. 또한 매우 광범위한 요청이기도합니다.
정확히 무엇을하고 싶습니까? URL 형식, 존재 여부 또는 무엇을 확인 하시겠습니까? 수행하려는 작업에 따라 여러 가지 가능성이 있습니다.
정규식은 URL 형식을 확인할 수 있습니다. 그러나 복잡한 정규 표현식조차도 유효한 URL을 처리하도록 보장 할 수 없습니다.
예를 들어 간단한 정규식을 사용하면 다음 호스트를 거부합니다.
http://invalid##host.com
그러나 그것은 허용합니다
http://invalid-host.foo
기존 TLD를 고려할 경우 유효한 호스트는 아니지만 유효한 호스트입니다. 실제로 다음과 같은 호스트 이름이므로 도메인이 아닌 호스트 이름의 유효성을 검사하려는 경우 솔루션이 작동합니다.
http://host.foo
뿐만 아니라 다음 중 하나
http://localhost
이제 몇 가지 해결책을 알려 드리겠습니다.
도메인의 유효성을 검사하려면 정규식을 잊어야합니다. 현재 사용 가능한 최상의 솔루션은 Mozilla가 유지 관리하는 목록 인 공개 접미사 목록입니다. 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뿐만 아니라 리디렉션도 허용해야합니다.
# 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
scheme없이 URL을 허용하고 domain zone 및 ip-hostnames를 확인하는 valid_url 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과 일치하도록 정규 표현식을 변경했습니다.
나를 위해 일한 해결책은 다음과 같습니다.
validates_format_of :url, :with => /\A(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w\.-]*)*\/?\Z/i
첨부 한 예제 중 일부를 사용하려고했지만 URL을 다음과 같이 지원하고 있습니다.
^와 $를 사용하면 Rails 유효성 검사기에서이 경고 보안을 볼 수 있으므로 A와 Z의 사용에 주목하십시오.
Valid ones:
'www.crowdint.com'
'crowdint.com'
'http://crowdint.com'
'http://www.crowdint.com'
Invalid ones:
'http://www.crowdint. com'
'http://fake'
'http:fake'
최근에 같은 문제가 발생했지만 (Rails 앱에서 URL을 확인해야했지만) 유니 코드 URL의 추가 요구 사항 (예 :)에 대처해야했습니다 http://кц.рф
...
몇 가지 솔루션을 연구하고 다음을 발견했습니다.
- 가장 먼저 제안되는 것은를 사용하는 것입니다
URI.parse
. 자세한 내용은 Simone Carletti의 답변을 확인하십시오. 이것은 정상적으로 작동하지만 유니 코드 URL에는 적합하지 않습니다. - 내가 본 두 번째 방법은 Ilya Grigorik의 방법입니다. http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/ 기본적으로 그는 URL; 작동하면 유효합니다 ...
- 내가 찾은 세 번째 방법 (및 내가 선호하는 방법)은 stdlib 대신 gem을
URI.parse
사용하는 것과 비슷 하지만 접근 방식 입니다. 이 접근법은 여기에 자세히 설명되어 있습니다 : http://rawsyntax.com/blog/url-validation-in-rails-3-and-ruby-in-general/addressable
URI
다음은 David James가 게시 한 유효성 검사기 의 업데이트 버전입니다 . 그것은 Benjamin Fleischer에 의해 출판되었습니다 . 한편, 나는 여기 에서 찾을 수있는 업데이트 된 포크를 밀었다 .
require 'addressable/uri'
# Source: http://gist.github.com/bf4/5320847
# Accepts options[:message] and options[:allowed_protocols]
# spec/validators/uri_validator_spec.rb
class UriValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
uri = parse_uri(value)
if !uri
record.errors[attribute] << generic_failure_message
elsif !allowed_protocols.include?(uri.scheme)
record.errors[attribute] << "must begin with #{allowed_protocols_humanized}"
end
end
private
def generic_failure_message
options[:message] || "is an invalid URL"
end
def allowed_protocols_humanized
allowed_protocols.to_sentence(:two_words_connector => ' or ')
end
def allowed_protocols
@allowed_protocols ||= [(options[:allowed_protocols] || ['http', 'https'])].flatten
end
def parse_uri(value)
uri = Addressable::URI.parse(value)
uri.scheme && uri.host && uri
rescue URI::InvalidURIError, Addressable::URI::InvalidURIError, TypeError
end
end
...
require 'spec_helper'
# Source: http://gist.github.com/bf4/5320847
# spec/validators/uri_validator_spec.rb
describe UriValidator do
subject do
Class.new do
include ActiveModel::Validations
attr_accessor :url
validates :url, uri: true
end.new
end
it "should be valid for a valid http url" do
subject.url = 'http://www.google.com'
subject.valid?
subject.errors.full_messages.should == []
end
['http://google', 'http://.com', 'http://ftp://ftp.google.com', 'http://ssh://google.com'].each do |invalid_url|
it "#{invalid_url.inspect} is a invalid http url" do
subject.url = invalid_url
subject.valid?
subject.errors.full_messages.should == []
end
end
['http:/www.google.com','<>hi'].each do |invalid_url|
it "#{invalid_url.inspect} is an invalid url" do
subject.url = invalid_url
subject.valid?
subject.errors.should have_key(:url)
subject.errors[:url].should include("is an invalid URL")
end
end
['www.google.com','google.com'].each do |invalid_url|
it "#{invalid_url.inspect} is an invalid url" do
subject.url = invalid_url
subject.valid?
subject.errors.should have_key(:url)
subject.errors[:url].should include("is an invalid URL")
end
end
['ftp://ftp.google.com','ssh://google.com'].each do |invalid_url|
it "#{invalid_url.inspect} is an invalid url" do
subject.url = invalid_url
subject.valid?
subject.errors.should have_key(:url)
subject.errors[:url].should include("must begin with http or https")
end
end
end
유효한 주소로 구문 분석 된 이상한 HTTP URI가 여전히 있음에 유의하십시오.
http://google
http://.com
http://ftp://ftp.google.com
http://ssh://google.com
다음은 예제를 다루는 gem 의 문제입니다addressable
.
I use a slight variation on lafeber solution above. It disallows consecutive dots in the hostname (such as for instance in www.many...dots.com
):
%r"\A(https?://)?[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]{2,6}(/.*)?\Z"i
URI.parse
seems to mandate scheme prefixing, which in some cases is not what you may want (e.g. if you want to allow your users to quickly spell URLs in forms such as twitter.com/username
)
I have been using the 'activevalidators' gem and it's works pretty well (not just for urls validation)
you can find it here
It's all documented but basically once the gem added you'll want to add the following few lines in an initializer say : /config/environments/initializers/active_validators_activation.rb
# Activate all the validators
ActiveValidators.activate(:all)
(Note : you can replace :all by :url or :whatever if you just want to validate specific types of values)
And then back in your model something like this
class Url < ActiveRecord::Base
validates :url, :presence => true, :url => true
end
Now Restart the server and that should be it
You can validate multiple urls using something like:
validates_format_of [:field1, :field2], with: URI.regexp(['http', 'https']), allow_nil: true
https://github.com/perfectline/validates_url is a nice and simple gem that will do pretty much everything for you
Recently I had this same issue and I found a work around for valid urls.
validates_format_of :url, :with => URI::regexp(%w(http https))
validate :validate_url
def validate_url
unless self.url.blank?
begin
source = URI.parse(self.url)
resp = Net::HTTP.get_response(source)
rescue URI::InvalidURIError
errors.add(:url,'is Invalid')
rescue SocketError
errors.add(:url,'is Invalid')
end
end
The first part of the validate_url method is enough to validate url format. The second part will make sure the url exists by sending a request.
If you want simple validation and a custom error message:
validates :some_field_expecting_url_value,
format: {
with: URI.regexp(%w[http https]),
message: 'is not a valid URL'
}
And as a module
module UrlValidator
extend ActiveSupport::Concern
included do
validates :url, presence: true, uniqueness: true
validate :url_format
end
def url_format
begin
errors.add(:url, "Invalid url") unless URI(self.url).is_a?(URI::HTTP)
rescue URI::InvalidURIError
errors.add(:url, "Invalid url")
end
end
end
And then just include UrlValidator
in any model that you want to validate url's for. Just including for options.
URL validation cannot be handled simply by using a Regular Expression as the number of websites keep growing and new domain naming schemes keep coming up.
In my case, I simply write a custom validator that checks for a successful response.
class UrlValidator < ActiveModel::Validator
def validate(record)
begin
url = URI.parse(record.path)
response = Net::HTTP.get(url)
true if response.is_a?(Net::HTTPSuccess)
rescue StandardError => error
record.errors[:path] << 'Web address is invalid'
false
end
end
end
I am validating the path
attribute of my model by using record.path
. I am also pushing the error to the respective attribute name by using record.errors[:path]
.
You can simply replace this with any attribute name.
Then on, I simply call the custom validator in my model.
class Url < ApplicationRecord
# validations
validates_presence_of :path
validates_with UrlValidator
end
You could use regex for this, for me works good this one:
(^|[\s.:;?\-\]<\(])(ftp|https?:\/\/[-\w;\/?:@&=+$\|\_.!~*\|'()\[\]%#,]+[\w\/#](\(\))?)(?=$|[\s',\|\(\).:;?\-\[\]>\)])
I liked to monkeypatch the URI module to add the valid? method
inside config/initializers/uri.rb
module URI
def self.valid?(url)
uri = URI.parse(url)
uri.is_a?(URI::HTTP) && !uri.host.nil?
rescue URI::InvalidURIError
false
end
end
참고URL : https://stackoverflow.com/questions/7167895/rails-whats-a-good-way-to-validate-links-urls
'IT story' 카테고리의 다른 글
.dex 파일의 메소드 참조 수는 64k API 17을 초과 할 수 없습니다 (0) | 2020.07.12 |
---|---|
오류 : 항목의 널값 : incrementalFolder = null (0) | 2020.07.12 |
Java에서 ArrayList의 교차 및 결합 (0) | 2020.07.12 |
명령 행을 사용하여 단일 테이블을 mysql 데이터베이스로 가져 오는 방법 (0) | 2020.07.12 |
Linux cat 명령을 사용하여 텍스트를 파일에 쓸 수 있습니까? (0) | 2020.07.12 |