Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如果URL为';不在那里吗?_Ruby On Rails_Ruby_Regex_Validation_Url - Fatal编程技术网

Ruby on rails 如果URL为';不在那里吗?

Ruby on rails 如果URL为';不在那里吗?,ruby-on-rails,ruby,regex,validation,url,Ruby On Rails,Ruby,Regex,Validation,Url,我在模型中使用这个正则表达式来验证用户提交的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" } 你知道我怎么做吗?我对验证和正则表达式几乎没有经验。不要

我在模型中使用这个正则表达式来验证用户提交的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" }

你知道我怎么做吗?我对验证和正则表达式几乎没有经验。

不要对正则表达式执行此操作,请使用将其分离,然后查看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

使用URI库也可以很容易地清除任何可能有人试图放入URL的胡言乱语(如userinfo)。

如果URL不存在,请使用before筛选器添加它:

before_validation :smart_add_url_protocol

protected

def smart_add_url_protocol
  unless url[/\Ahttp:\/\//] || url[/\Ahttps:\/\//]
    self.url = "http://#{url}"
  end
end

保留您的验证,这样,如果他们输入错误,他们就可以更正协议。

我不会在验证中尝试这样做,因为它实际上不是验证的一部分

让验证人员有选择地检查它;如果他们搞砸了,这将是一个验证错误,这是好的

考虑使用回调(
在\u create
之后,
在\u validation
之后,无论什么)来预先编写协议(如果还没有协议)


(我对其他答案投了赞成票;我认为它们都比我的好。但这里有另一个选项:)

根据mu的答案,下面是我在模型中使用的代码。当保存链接而不需要模型过滤器时,将运行此命令。调用默认的save方法需要Super

def link=(_link)
    u=URI.parse(_link)

    if (!u.scheme)
        link = "http://" + _link
    else
        link = _link
    end
    super(link)
end

公认的答案很好。 但是如果字段(url)是可选的,它可能会为
nil
类引发错误,例如
undefined method
+。 应解决以下问题:

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
前言、理由和应如何做 我讨厌人们在验证之前在
中更改模型。然后,当某一天由于某种原因模型需要通过save(validate:false)持久化时,一些假定总是在指定字段上运行的过滤器就不会运行了。当然,拥有无效数据通常是您想要避免的事情,但是如果不使用,就不需要这样的选项。它的另一个问题是,每次您向模型询问它是否有效时,这些修改也会发生。仅仅询问模型是否有效可能会导致模型被修改,这一事实是出乎意料的,甚至是不必要的。如果我必须选择一个钩子,那么在保存钩子之前,我会选择
。但是,这对我来说不行,因为我们为模型提供了预览视图,这会破坏预览视图中的URI,因为钩子永远不会被调用。为此,我决定最好将概念分离到一个模块或关注点中,并为应用“猴子补丁”提供一种很好的方法,确保更改字段值始终通过一个过滤器运行,如果缺少,则添加一个默认协议

模块 在您的模型中 作为关注点 如果出于某种原因,您更愿意使用Rails关注点模式,那么很容易将上述模块转换为关注点模块(除了使用
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
另外,上述方法在Rails 3和Mongoid 2上进行了测试。

P.P.S如果您发现此方法的重新定义和别名太神奇,您可以选择不重写该方法,而是使用虚拟字段模式,就像密码(虚拟,可批量分配)和加密的\u密码(持久化,不可批量分配)一样,并使用清理\u url(虚拟,可批量分配)和url(获取持久化的、非批量分配的)。

使用前面提到的一些regexp,这里有一个覆盖模型上默认url的简便方法(例如,如果您的ActiveRecord模型有一个“url”列)


我必须在同一个模型上对多个列执行此操作

  before_validation :add_url_protocol

  def add_url_protocol
    [
      :facebook_url, :instagram_url, :linkedin_url,
      :tiktok_url, :youtube_url, :twitter_url, :twitch_url
    ].each do |url_method|
      url = self.send(url_method)

      if url.present? && !(%w{http https}.include?(URI.parse(url).scheme))
        self.send("#{url_method.to_s}=", 'https://'.concat(url)) 
      end
    end
  end

我们使用可寻址来实现这一点。但是,如果URL中没有方案,这有点奇怪,因为它认为主机是路径。@d11wtq我刚刚切换到可寻址,以便在URL中获得合理和一致的UTF-8支持。我必须对这种肮脏的伎俩提出建议。它“有效”对于像
/pancakes
这样的简单路径,为什么会有人想要在路径上强制协议呢?然而,如果我们谈论的是“web地址”正如正常人理解和编写它们一样,使用URI将无法正确解析它们。这是因为大多数人在“web地址”中省略了指示权限定义开始的双正斜杠。事实上,我相信许多人认为它们属于协议定义,但它们不属于。待续。。。(为超长的双帖子感到抱歉)当“URL”然后使用一些符合规范的组件(如Rubys URI)解析这些对象,结果是URI对象中没有主机,但它被推断为一个完整的路径。这不太可能是预期的结果,并给人一种错误的印象,即您可以使用一个正确解析的URI对象,但如果有人修改任何其组件的结果将是令人惊讶的。要正确地将“web地址”解析为URI,您应该始终首先确保前向破折号已就位。@muistooshort您的示例缺少一些细节,但我可以看到“#prepend http://并重试”部分的两个明显实现。更自然的解决方案
u.scheme=“http;u.to_s==”http:www.example.com“#oops,发生了什么事?
或者您将其预先添加到原始字符串并再次解析。
u=“http://{orig#u string}”
。但是,如果有人给您一个协议相对URI,则此操作将失败,因为您最终会得到”http:////www.example.com“在重新分析后,
u.host==nil&&u.path==”//www.Simult.com“,这是不正确的,这就是为什么我认为这是非常危险的。<代码>除非是我自己。URL[/http:s/\//] 对我来说不是很有效。除非自己。URL [/http:///] ]我自己必须做<代码>。URL[/http:\/\/]
这不应该是一个验证,而仅仅是保存前的一个
钩子。验证的目的是使实例无效(防止它
#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
def url
  _url = read_attribute(:url).try(:downcase)
  if(_url.present?)
    unless _url[/\Ahttp:\/\//] || _url[/\Ahttps:\/\//]
      _url = "http://#{_url}"
    end
  end
_url
end
  before_validation :add_url_protocol

  def add_url_protocol
    [
      :facebook_url, :instagram_url, :linkedin_url,
      :tiktok_url, :youtube_url, :twitter_url, :twitch_url
    ].each do |url_method|
      url = self.send(url_method)

      if url.present? && !(%w{http https}.include?(URI.parse(url).scheme))
        self.send("#{url_method.to_s}=", 'https://'.concat(url)) 
      end
    end
  end