Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/62.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 rails正在使用URI.parse验证url,并引发意外结果_Ruby On Rails_Ruby - Fatal编程技术网

Ruby on rails rails正在使用URI.parse验证url,并引发意外结果

Ruby on rails rails正在使用URI.parse验证url,并引发意外结果,ruby-on-rails,ruby,Ruby On Rails,Ruby,下面我将验证rails应用程序中服务类中的url。测试返回false,但在控制台中,当我使用Ruby的URI类解析给定的url时,不会出现错误。我不认为我的代码中有任何拼写错误-有任何建议我哪里出错了吗 class UrlService attr_accessor :uri def initialize(uri) @uri = uri end def valid? begin uri = URI.parse(uri) !uri.host

下面我将验证rails应用程序中服务类中的url。测试返回false,但在控制台中,当我使用Ruby的URI类解析给定的url时,不会出现错误。我不认为我的代码中有任何拼写错误-有任何建议我哪里出错了吗

class UrlService
  attr_accessor :uri

  def initialize(uri)
    @uri = uri
  end

  def valid?
    begin
      uri = URI.parse(uri)
      !uri.host.nil? && uri.kind_of?(URI::HTTP)
    rescue URI::InvalidURIError
      false
    end
  end

end
试验


您的问题实际上是Ruby gotcha,在这一行:

uri = URI.parse(uri)
您希望将
uri
重新定义为
uri
的解析版本。实际上,Ruby看到“哦,您正在定义一个新的局部变量
uri
”;新的局部变量现在优先于使用attr\u访问器定义的方法
uri
。出于某种原因,Ruby在局部变量赋值期间将自引用计算为
nil
。这是一个例子

因此,上面的语句会导致
URI.parse
始终在
nil
的值上执行,这就是无论您将该URI设置为什么,测试都会失败的原因。要解决此问题,只需使用不同的变量名:

parsed_uri = URI.parse(uri)

附录:证明我不是在编造的简短例子
这和你遇到的问题是一样的;只需一个
按钮,即可将
插入检查值。它打印出
nil

您的问题实际上是Ruby gotcha,在这一行:

uri = URI.parse(uri)
irb(main):011:0> class Foo; def bar; "http://www.google.com"; end; end
=> :bar
irb(main):012:0> Foo.new.instance_exec { bar }
=> "http://www.google.com"
irb(main):013:0> Foo.new.instance_exec { bar = (puts bar.inspect) }
nil
=> nil
您希望将
uri
重新定义为
uri
的解析版本。实际上,Ruby看到“哦,您正在定义一个新的局部变量
uri
”;新的局部变量现在优先于使用attr\u访问器定义的方法
uri
。出于某种原因,Ruby在局部变量赋值期间将自引用计算为
nil
。这是一个例子

因此,上面的语句会导致
URI.parse
始终在
nil
的值上执行,这就是无论您将该URI设置为什么,测试都会失败的原因。要解决此问题,只需使用不同的变量名:

parsed_uri = URI.parse(uri)

附录:证明我不是在编造的简短例子
这和你遇到的问题是一样的;只需一个
按钮,即可将
插入检查值。它打印
nil

如果预期的用途是验证模型,您可能希望将其作为自定义验证器而不是服务来编写

irb(main):011:0> class Foo; def bar; "http://www.google.com"; end; end
=> :bar
irb(main):012:0> Foo.new.instance_exec { bar }
=> "http://www.google.com"
irb(main):013:0> Foo.new.instance_exec { bar = (puts bar.inspect) }
nil
=> nil
# lib/validators/uri_validator.rb
class UriValidator < ActiveModel::Validator
  def validate_each(record, attribute, value)
    begin
      uri = URI.parse(value)
    rescue URI::InvalidURIError
    end
    if uri && uri.host && uri.kind_of?(URI::HTTP)
      record.errors.add attribute,
    end
  end
end
最直接的测试方法是通过使用验证器的模型类:

require "rails_helper"
RSpec.describe Thing, type: :model do
  describe "validations" do
    describe "url" do
      it "does not allow an invalid URL" do
        thing = Thing.new(url: 'foo')
        thing.valid
        expect(thing.errors).to have_key :url
      end
      it "allows a valid URL" do
        thing = Thing.new(url: 'https://www.google.com/')
        thing.valid
        expect(thing.errors).to have_key :url
      end
    end
  end
end

如果预期用途是验证模型,您可能希望将其作为自定义验证器而不是服务来编写

# lib/validators/uri_validator.rb
class UriValidator < ActiveModel::Validator
  def validate_each(record, attribute, value)
    begin
      uri = URI.parse(value)
    rescue URI::InvalidURIError
    end
    if uri && uri.host && uri.kind_of?(URI::HTTP)
      record.errors.add attribute,
    end
  end
end
最直接的测试方法是通过使用验证器的模型类:

require "rails_helper"
RSpec.describe Thing, type: :model do
  describe "validations" do
    describe "url" do
      it "does not allow an invalid URL" do
        thing = Thing.new(url: 'foo')
        thing.valid
        expect(thing.errors).to have_key :url
      end
      it "allows a valid URL" do
        thing = Thing.new(url: 'https://www.google.com/')
        thing.valid
        expect(thing.errors).to have_key :url
      end
    end
  end
end

顺便说一句,如果你打算在模型中使用它,那么把它写成一个而不是一个服务是有意义的。顺便说一句,如果你打算在模型中使用它,那么把它写成一个而不是一个服务是有意义的。我想是这样的。谢谢你的解释。我以为是这样的。谢谢你的解释。谢谢你的评论。我在最初发布的链接中看到了这个选项。我的类不是ActiveRecord或ActiveModel类。谢谢您的评论。我在最初发布的链接中看到了这个选项。我的类不是ActiveRecord或ActiveModel类。