jay*_*jay 122 ruby regex validation url ruby-on-rails
我想知道如何最好地验证Rails中的URL.我在考虑使用正则表达式,但不确定这是否是最好的做法.
而且,如果我使用正则表达式,有人可以向我推荐一个吗?我还是Regex的新手.
Sim*_*tti 141
验证URL是一项棘手的工作.这也是一个非常广泛的要求.
你到底想做什么?您想验证URL的格式,存在还是什么?根据您的要求,有几种可能性.
正则表达式可以验证URL的格式.但即使是复杂的正则表达式也无法确保您处理有效的URL.
例如,如果您使用简单的正则表达式,它可能会拒绝以下主机
http://invalid##host.com
Run Code Online (Sandbox Code Playgroud)
但它会允许
http://invalid-host.foo
Run Code Online (Sandbox Code Playgroud)
如果您考虑现有TLD,那么这是一个有效的主机,但不是有效的域.实际上,如果要验证主机名而不是域,则该解决方案将起作用,因为以下是有效的主机名
http://host.foo
Run Code Online (Sandbox Code Playgroud)
以及以下一个
http://localhost
Run Code Online (Sandbox Code Playgroud)
现在,让我给你一些解决方案.
如果要验证域,则需要忘记正则表达式.目前可用的最佳解决方案是公共后缀列表,由Mozilla维护的列表.我创建了一个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
Run Code Online (Sandbox Code Playgroud)
您甚至可以决定使其更具限制性.例如,如果您希望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
Run Code Online (Sandbox Code Playgroud)
当然,您可以对此方法应用大量改进,包括检查路径或方案.
最后但同样重要的是,您还可以将此代码打包到验证器中:
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
Run Code Online (Sandbox Code Playgroud)
小智 97
我在模特里面使用了一个衬垫:
validates :url, format: URI::regexp(%w[http https])
我认为它足够好并且易于使用.此外,它应该在理论上等同于Simone的方法,因为它在内部使用相同的正则表达式.
jlf*_*aux 53
遵循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
Run Code Online (Sandbox Code Playgroud)
然后使用
validates :url, :presence => true, :url => true
Run Code Online (Sandbox Code Playgroud)
在你的模型中.
dol*_*nko 26
还有validate_url gem(这只是Addressable::URI.parse
解决方案的一个很好的包装器).
只需添加
gem 'validate_url'
Run Code Online (Sandbox Code Playgroud)
到你的Gemfile
,然后你可以在模特
validates :click_through_url, url: true
Run Code Online (Sandbox Code Playgroud)
Ste*_*son 14
这个问题已经回答了,但到底是什么,我提出了我正在使用的解决方案.
正则表达式适用于我遇到的所有网址.如果没有提到协议,那么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
Run Code Online (Sandbox Code Playgroud)
和...
# 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
Run Code Online (Sandbox Code Playgroud)
小智 12
您还可以尝试使用valid_url gem,它允许没有方案的URL,检查域区域和ip-hostnames.
将它添加到您的Gemfile:
gem 'valid_url'
然后在模型中:
class WebSite < ActiveRecord::Base
validates :url, :url => true
end
Run Code Online (Sandbox Code Playgroud)
laf*_*ber 10
只需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
Run Code Online (Sandbox Code Playgroud)
编辑:更改正则表达式以匹配参数网址.
Her*_*aña 10
对我有用的解决方案是:
validates_format_of :url, :with => /\A(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w\.-]*)*\/?\Z/i
Run Code Online (Sandbox Code Playgroud)
我确实尝试使用你附加的一些例子但我支持url如下:
注意使用A和Z,因为如果使用^和$,您将从Rails验证器中看到此警告安全性.
Valid ones:
'www.crowdint.com'
'crowdint.com'
'http://crowdint.com'
'http://www.crowdint.com'
Invalid ones:
'http://www.crowdint. com'
'http://fake'
'http:fake'
Run Code Online (Sandbox Code Playgroud)
我最近遇到了同样的问题(我需要在Rails应用程序中验证网址)但我不得不应对unicode网址的额外要求(例如http://??.??
)...
我研究了几个解决方案,并发现了以下内容:
URI.parse
.有关详细信息,请查看Simone Carletti的答案.这可行,但不适用于unicode网址.URI.parse
但使用addressable
gem而不是URI
stdlib的方法.这种方法在这里详述:http://rawsyntax.com/blog/url-validation-in-rails-3-and-ruby-in-general/