Usando uma expressão regular para validar um campo em um modelo e um segmento em uma rota

É um tanto comum em uma aplicação Rails querer incluir um
slug de URL customizado como parte de um modelo. Por exemplo, se você tem um Usermodelo e deseja que
esses usuários tenham uma página de perfil acessível em /users/john-smith,
você deseja armazenar esse "john-smith"valor no modelo e garantir que
ele seja único. Eu chamo esse campo de “lesma”.

Digamos que você queira permitir que os usuários editem seus próprios slug e decidam o que será inserido no
URL de seu perfil. Neste caso, você deseja adicionar algumas restrições aos
caracteres permitidos na lesma, para que o Little Bobby TABLES não
lhe faça uma visita indesejada.

Portanto, você deseja uma validação de formato de expressão regular no atributo de modelo
User#slug, mas também deseja poder usar a mesma expressão regular para
corresponder a um segmento de caminho em seu arquivo de rotas. Eu faço isso usando uma constante para a expressão regular de formato não
ancorado na parte superior do meu modelo:

class User < ActiveRecord::Base

SLUG_FORMAT
= /([[:lower:]]|[0-9]+-?[[:lower:]])(-[[:lower:]0-9]+|[[:lower:]0-9])*/

# ...

Em seguida, adiciono uma validação ActiveModel no slugcampo e adiciono ancoragem
para tornar a validação do campo do modelo segura ne outras
entradas furtivas que escapariam de um validador de formato não ancorado:

validates :slug, uniqueness: {case_sensitive: false},
format
: {with: Regexp.new('A' + SLUG_FORMAT.source + 'z')}

Observe o uso das classes de caracteres RegExp Ae zpara o início e o
final da string, não ^ , $ou Z. Você pode ler os
documentos do RegExp
para entender as diferenças, mas a essência é essa Ae zsignifica
exatamente o início e o fim de uma string, ponto final. Os outros correspondem a diferentes
pontos de ancoragem em uma string.

Agora, como armazenei a versão não ancorada da expressão regular de formato em
uma constante, posso usar essa mesma constante em meu arquivo de rotas:

constraints(slug: User::SLUG_FORMAT, id: /d+/) do
get '/users/:slug' => 'users#show', as: 'user'
end

Agora, se eu decidir mudar o formato de minhas lesmas permitidas, só preciso
mudá-lo em um lugar: minha SLUG_FORMATconstante. Existem outras coisas sofisticadas que
você pode fazer com os slugs, como gerá-los automaticamente a partir de um namecampo e testar
seu comportamento por completo, mas vou deixar isso para outra hora.