了解 Rails URL slugs的限制性路径验证器

74 阅读1分钟

当我们从模型ID转向slugs时,我们必须注意控制器动作的名称碰撞。

前段时间,我写了关于在Rails中实现slugs的最简单方法。虽然实现起来很简单,但这并不是我们要注意的全部。一旦我们从ID转移到slugs,我们需要确保我们的用户不会选择会破坏应用程序的slugs。

/teams/:slug 路径可以覆盖或被/teams/controller_action_name 覆盖。

下面的片段将是一个好的开始,因为字母数字的限制对一个URL标识符来说是很好的。

class Team < ApplicationRecord
  ...

  validates :slug,
    presence: true,
    uniqueness: true,
    length: {minimum: 2, maximum: 30},
    format: {with: /\A[a-zA-Z0-9]+\Z/}

但这是不够的。输入的slugs仍然可能与常规的应用路径发生冲突。如果有人选择你的控制器动作的名称呢?或者你想为未来保留的东西?

为了解决这个问题,我们可以为这个目的写一个自定义验证器。

# app/validators/restricted_paths_validator.rb

class RestrictedPathsValidator < ActiveModel::Validator
  RESTRICTED_PATHS = TeamsController.action_methods + [
    "admin",
    "admins"
  ]

  def validate(record)
    if RESTRICTED_PATHS.include?(record.slug)
      record.errors.add :slug, :restricted_path
    end
  end
end

然后把它包含在你的模型中。

  # Avoid slug conflicts with routes
  validates_with ::RestrictedPathsValidator

验证器是限制当前所有来自控制器的动作,更多的路径可以在上面添加。

如果我们想提供一个自定义的错误信息,我们可以添加一个I18n条目,activerecord.errors.messages.restricted_path

en:
  activerecord:
    errors:
      messages:
        restricted_path: not allowed