自定义EmailValidator不起作用

时间:2014-06-03 12:21:43

标签: ruby-on-rails ruby validation

我有一个基于ruby指南的自定义电子邮件验证程序类:

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
     record.errors[attribute] << (options[:message] || "is not an email")
    end
  end
end

此课程位于app / validators / email_validator.rb

型号:

class User < ActiveRecord::Base

    validates :name, :email, presence: true
validates :email, email: true

end

错误:

`rescue in block in validates': Unknown validator: 'EmailValidator' (ArgumentError)

运行测试(rspec)时会出现此错误。

5 个答案:

答案 0 :(得分:9)

我刚遇到这个问题,这是真正的解决方案。

事实证明,从Rails文档复制和粘贴代码可能会留下混合空格字符,这会导致代码错误地解析。这是a sample gist diff of an original and corrected version of my validator。注意一切看起来都一样,但不知何故有一个差异!如果您运行第一个版本,您将收到相同的错误:

NameError: undefined local variable or method 'record' for WholeNumberValidator:Class

如果我们检查字节,我们会看到差异:

# Standard Space
' '.bytes # => [32]: U+0020, Space
# Space from Copy/Paste
' '.bytes # => [194, 160]: U+00A0, No break space

替换文件中的空格,一切都应该有效!

答案 1 :(得分:2)

这个问题有几种解决方案。问题是您的EmailValidator不在加载路径上,因此Rails不知道如何找到它。以下任何一种解决方案都应该有效:

  1. 在您要使用它的文件中明确要求email_validator,或者甚至在初始值设定项中如下:

    # config/initializers/validators.rb
    require "#{Rails.root}/app/validators/email_validator"
    
  2. validators目录添加到应用程序的自动加载路径中:

    # config/application.rb
    config.autoload_paths += %W["#{config.root}/app/validators/"]
    
  3. email_validator放在自动加载路径上的目录中,如app/models/email_validator.rblib/email_validator.rb

  4. 就个人而言,#2是我首选的解决方案,因为它通过为验证器指定特定目录为您的应用提供了一个很好的结构,并且在添加新的验证器时您将来不需要更改任何代码。

答案 2 :(得分:1)

要使此目录app/validators/对rails autoloader可见,您需要将其添加到application.rb

# config/application.rb

# ...

# add custom validators path
config.autoload_paths += %W["#{config.root}/app/validators/"]

然后重新启动rails服务器

答案 3 :(得分:0)

试试这个

def validate_each(record, attribute, value)
    begin
      r =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
    rescue Exception => e
      r = false
    end
    record.errors[attribute] << (options[:message] || "is not an email") unless r
end

专业提示:

看起来您正在寻找电子邮件验证工具,为什么不使用这个

require 'mail'
class EmailValidator < ActiveModel::EachValidator
  def validate_each(record,attribute,value)
    begin
      m = Mail::Address.new(value)
      # We must check that value contains a domain and that value is an email address
      r = m.domain && m.address == value
      t = m.__send__(:tree)
      # We need to dig into treetop
      # A valid domain must have dot_atom_text elements size > 1
      # user@localhost is excluded
      # treetop must respond to domain
      # We exclude valid email values like <user@localhost.com>
      # Hence we use m.__send__(tree).domain
      r &&= (t.domain.dot_atom_text.elements.size > 1)
    rescue Exception => e   
      r = false
    end
    record.errors[attribute] << (options[:message] || "is invalid") unless r
  end
end

请务必先加载此课程,我猜您知道这样做(正如许多其他答案已经以一种好的方式描述的那样)

答案 4 :(得分:0)

我注意到Hamed的解决方案#1部分适用于你,但你得到“未定义的局部变量或方法”

如果您尝试在=~比较运算符的左侧放置一个变量,则会出现错误。

http://ruby-doc.org/core-2.1.1/Regexp.html#method-i-3D-7E

除非是

的正确格式
unless /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i =~ value