Rails-不能以字符开头或结尾的用户名

时间:2018-08-20 19:05:26

标签: ruby-on-rails ruby regex validation ruby-on-rails-5

最初问有关用户名正则表达式的问题:Usernames that cannot start or end with characters

如何使用Ruby on Rails的正确语法实现这一目标?

这是我当前的User.rb验证:

validates_format_of :username, with: /\A[\w\._]{3,28}\z/i

此验证允许使用下划线和下划线,但目标是不允许在用户名的开头或结尾使用下划线和。

我正在尝试通过Rails regex实现这些规则:

  • 可以包含小写和大写字母和数字
  • 可以包含下划线和句点
  • 不能连续包含2个下划线
  • 不能连续包含两个句点
  • 不能以下划线或句号开头或结尾
  • 不能包含带有重音符号的字母
  • 长度必须在3到28个字母之间

有效:

Spicy_Pizza
97Indigos
Infinity.Beyond

无效:

_yahoo
powerup.
un__real
no..way

2 个答案:

答案 0 :(得分:3)

您可以使用

/\A(?=.{3,28}\z)[a-zA-Z0-9]+(?:[._][a-zA-Z0-9]+)*\z/

请参见Rubular demo

详细信息

  • \A-字符串的开头
  • (?=.{3,28}\z)-允许/要求到字符串末尾的换行符以外的3到28个字符
  • [a-zA-Z0-9]+-一个或多个ASCII字母/数字
  • (?:[._][a-zA-Z0-9]+)*-0个以上的序列:
    • [._]-一个._
    • [a-zA-Z0-9]+-一个或多个ASCII字母/数字
  • \z-字符串的结尾。

答案 1 :(得分:2)

尽管完全有可能,如Wiktor的答案所示,我的建议是不要在单个正则表达式中定义它,因为:

  • 除非您非常了解正则表达式,否则该解决方案很难理解。
  • 类似地,除非您非常了解正则表达式,否则解决方案很难用新要求进行更新
  • 通过一次性完成整个检查,如果验证失败,则不可避免地会收到一条通用错误消息,例如"Invalid Format",它不能解释为什么无效。然后,练习留给用户重新阅读非平凡的格式规则并了解原因。

相反,我建议您定义一个custom validation class,它可以分别执行这些检查(通过易于理解的方法),并在每次检查失败时添加不同的错误消息。

类似的东西:

# app/models/user.rb
class User < ApplicationRecord
  validates :username, presence: true, username: true
end

# app/validators/username_validator.rb
class UsernameValidator < ActiveModel::EachValidator
  def validate(record, attribute, value)
    validate_length(record, attribute, value)
    validate_allowed_chars(record, attribute, value)
    validate_sequential_chars(record, attribute, value)
    validate_first_and_last_chars(record, attribute, value)
  end

private

  def validate_length(record, attribute, value)
    unless value.length >= 3 && value.length <= 28
      record.errors[attribute] << "must be between 3 and 28 characters long"
    end
  end

  def validate_allowed_chars(record, attribute, value)
    unless value =~ /\A[._a-zA-Z0-9]*\z/
      record.errors[attribute] << "must only contain periods, underscores, a-z, A-Z or 0-9"
    end
  end

  def validate_sequential_chars(record, attribute, value)
    if value =~ /[._]{2}/
      record.errors[attribute] << "cannot contain two consecutive periods or underscores"
    end
  end

  def validate_first_and_last_chars(record, attribute, value)
    if value =~ /\A[._]/ || value =~ /[._]\z/
      record.errors[attribute] << "cannot start/end with a period or underscore"
    end
  end
end

例如,您在上面问:“如果我需要扩展它以仅允许小写字母怎么办?”我认为现在很明显如何更新代码以适应这种行为,但是要明确一点-您需要做的只是:

def validate_allowed_chars(record, attribute, value)
  unless value =~ /\A[._a-z0-9]*\z/
    record.errors[attribute] << "must only contain periods, underscores, a-z or 0-9"
  end
end

您现在还可以很容易地为这些验证检查编写测试,并断言通过对错误消息的内容进行验证来正确执行验证。 ;当所有验证失败都导致相同的错误时,这是​​不可能的,

此方法的另一个好处是可以轻松共享代码(也许会有一些细微的行为差异)。您可以对多个属性或多个模型执行相同的验证,也许具有不同的允许长度或格式。