33 ruby regex validation url ruby-on-rails
我在我的模型中使用此正则表达式来验证用户提交的URL.我不想强迫用户输入http部分,但是如果它不在那里,我想自己添加它.
validates :url, :format => { :with => /^((http|https):\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+).[a-z]{2,5}(:[0-9]{1,5})?(\/.)?$/ix, :message => " is not valid" }
Run Code Online (Sandbox Code Playgroud)
知道我怎么能这样做吗?我对验证和正则表达式的经验很少..
Dou*_*rer 70
如果不存在,请使用前置过滤器添加它:
before_validation :smart_add_url_protocol
protected
def smart_add_url_protocol
unless self.url[/\Ahttp:\/\//] || self.url[/\Ahttps:\/\//]
self.url = "http://#{self.url}"
end
end
Run Code Online (Sandbox Code Playgroud)
保留您的验证,如果他们输错,他们可以更正协议.
mu *_*ort 36
不要使用正则表达式,使用URI.parse
它将它拉开,然后查看URL上是否有方案:
u = URI.parse('/pancakes')
if(!u.scheme)
# prepend http:// and try again
elsif(%w{http https}.include?(u.scheme))
# you're okay
else
# you've been give some other kind of
# URL and might want to complain about it
end
Run Code Online (Sandbox Code Playgroud)
使用URI库还可以轻松清除某人可能尝试放入URL的任何流浪废话(例如userinfo).
接受的答案是可以接受的.但是如果字段(url)是可选的,它可能会引发错误,例如undefined method
+ nil
类.以下内容应解决:
def smart_add_url_protocol
if self.url && !url_protocol_present?
self.url = "http://#{self.url}"
end
end
def url_protocol_present?
self.url[/\Ahttp:\/\//] || self.url[/\Ahttps:\/\//]
end
Run Code Online (Sandbox Code Playgroud)
我讨厌人们在before_validation
钩子上改变模型。然后,当有一天由于某种原因模型需要使用 save(validate: false) 进行持久化时,一些本来应该始终在指定字段上运行的过滤器不会运行。当然,无效数据通常是您想要避免的事情,但如果不使用它,就不需要这样的选项。另一个问题是,每次您询问模型是否有效时,这些修改也会发生。事实上,简单地询问模型是否有效可能会导致模型被修改,这是意料之外的,甚至可能是不需要的。如果我必须选择一个钩子,我会选择before_save
钩子。但是,这对我来说不起作用,因为我们为模型提供了预览视图,并且这会破坏预览视图中的 URI,因为挂钩永远不会被调用。因此,我决定最好将概念分离到模块或关注点中,并提供一种应用“猴子补丁”的好方法,确保更改字段值始终通过过滤器运行,该过滤器添加默认协议(如果是)丢失的。
#app/models/helpers/uri_field.rb
module Helpers::URIField
def ensure_valid_protocol_in_uri(field, default_protocol = "http", protocols_matcher="https?")
alias_method "original_#{field}=", "#{field}="
define_method "#{field}=" do |new_uri|
if "#{field}_changed?"
if new_uri.present? and not new_uri =~ /^#{protocols_matcher}:\/\//
new_uri = "#{default_protocol}://#{new_uri}"
end
self.send("original_#{field}=", new_uri)
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
extend Helpers::URIField
ensure_valid_protocol_in_uri :url
#Should you wish to default to https or support other protocols e.g. ftp, it is
#easy to extend this solution to cover those cases as well
#e.g. with something like this
#ensure_valid_protocol_in_uri :url, "https", "https?|ftp"
Run Code Online (Sandbox Code Playgroud)
如果出于某种原因,您更愿意使用 Rails Concern 模式,可以很容易地将上述模块转换为关注模块(它的使用方式完全相同,除了您使用include Concerns::URIField
:
#app/models/concerns/uri_field.rb
module Concerns::URIField
extend ActiveSupport::Concern
included do
def self.ensure_valid_protocol_in_uri(field, default_protocol = "http", protocols_matcher="https?")
alias_method "original_#{field}=", "#{field}="
define_method "#{field}=" do |new_uri|
if "#{field}_changed?"
if new_uri.present? and not new_uri =~ /^#{protocols_matcher}:\/\//
new_uri = "#{default_protocol}://#{new_uri}"
end
self.send("original_#{field}=", new_uri)
end
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
PS 以上方法已使用 Rails 3 和 Mongoid 2 进行了测试。
PPS 如果您发现此方法的重新定义和别名太神奇,您可以选择不覆盖该方法,而是使用虚拟字段模式,就像密码一样(虚拟,可批量分配)和 crypto_password (持久化,不可批量分配)并使用 sanitize_url (虚拟,可批量分配)和 url (持久化,不可批量分配)。
归档时间: |
|
查看次数: |
18777 次 |
最近记录: |