【问题标题】:Rails validatation to ensure a username does not clash with an existing route?Rails 验证以确保用户名不会与现有路由冲突?
【发布时间】:2012-02-01 03:24:46
【问题描述】:

我想确保用户不能创建与我现有路由冲突的用户名。我还希望能够拒绝我可能定义的未来路线。我正在考虑这样做:

在模型中:

class User < ActiveRecord::Base
  @@invalid_usernames = %w()

  cattr_accessor :invalid_usernames

  validates :username, :exclusion { :in => @@invalid_usernames }
end

在一些初始化器中:

User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq

这是“Rails 方式”吗?有没有更好的办法?

【问题讨论】:

  • @iWasRobbed 抱歉,我删除了其他验证。这纯粹是为了避免与 非用户名路由 发生冲突。对于与其他用户名的冲突,我已经有了唯一性验证和数据库级约束。编辑:顺便说一句,如果你确实需要动态地做,你总是可以使用:in =&gt; lambda { ... }(这实际上是我应该在上面使用的,我相信)

标签: ruby-on-rails ruby-on-rails-3 validation activerecord activemodel


【解决方案1】:

这是我自己的答案,经过测试并使用 Rails 3.1.3 和 Ruby 1.9.3

app/models/user.rb

class User < ActiveRecord::Base
  class_attribute :invalid_usernames
  self.invalid_usernames = Set.new %w()

  validates :username, presence:   true,
                       uniqueness: { case_sensitive: false },
                       exclusion:  { in: lambda { self.invalid_usernames }}
end

config/application.rb

[:after_initialize, :to_prepare].each do |hook|
  config.send(hook) do
    User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq
  end
end

注意事项

我最初尝试在after_initialize 期间设置User.invalid_usernames,但发现它需要在to_prepare 期间设置(即在开发模式下每个 请求之前,first em> 在生产模式下请求),因为模型在每次请求之前在开发中重新加载并且原始设置丢失。

然而,我after_initialize 期间设置User.invalid_usernames,因为在测试环境中运行时,在to_prepare 期间路由似乎不可用。我为此尝试的另一个解决方法,它确实有效,是在to_prepare 期间强制加载路由:

config.to_prepare do
  Rails.application.reload_routes!
  User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq
end

我喜欢这个,因为它干脆易读。但我对每次请求都重新加载路由持谨慎态度,即使它只是处于开发模式。如果这意味着我完全理解其影响,我宁愿使用一些有点难以阅读的东西。接受批评!

当我发现前者适用于整个类层次结构时,我也放弃了 cattr_accessorclass_attribute(即在子类上更改其值会影响超类)

我还选择为User.invalid_usernames 使用Set,而不是数组,因为不需要存储和与欺骗进行比较,这是一个透明的变化。

我也改成了 Ruby 1.9 的哈希语法(:

【讨论】:

  • 如果你想更宽松一些,你也可以根据.verb过滤路由(尽管检查'''GET')。您可能想对通配符路由(/*page.html 等)做一些事情。还有一个after_initialize 钩子来确保你没有添加一个被当作用户名的路由也是一个好主意。
  • 您可以接受自己的答案(甚至还有badge for it),这当然是接受您自己的答案的好人选。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-21
  • 1970-01-01
  • 2016-04-06
  • 2021-04-11
  • 1970-01-01
相关资源
最近更新 更多