Вот мой собственный ответ, проверенный и работающий с 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
Примечания
Сначала я попытался установить User.invalid_usernames
во время after_initialize
, но обнаружил, что его нужно установить во время to_prepare
(то есть до каждого запросав режиме разработки и перед первым запросом в производственном режиме), поскольку модели перезагружаются в разработке перед каждым запросом, и первоначальная настройка теряется.
Однако я также установка User.invalid_usernames
во время after_initialize
, поскольку при работе в тестовой среде маршруты не доступны во время 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_accessor
для class_attribute
, когда узнал, что первое относится ко всей иерархии классов (т. Е. Изменение его значения в подклассе повлияет на суперкласс)
Я также решил использовать Set
для User.invalid_usernames
вместо массива, поскольку нет необходимости хранить и сравнивать с дупсами, и это было прозрачное изменение.
Я также изменил синтаксис хэша Ruby 1.9 (: