O que aconteceu?
Por dentro do app
Quando alguém clica em Postar recado, o caminho agora tem uma pergunta no meio:
- O controller monta o recado com o que veio do formulário (
Message.new). - O model confere as regras (
save). Se estiver tudo certo, guarda o recado no banco de dados e respondetrue. Se faltar alguma coisa, não guarda nada, anota o que faltou emerrorse respondefalse. - O controller decide o que fazer com a resposta: se deu certo, volta para o mural de recados; se não, mostra a página de novo (
render). - A view mostra o formulário com o que a pessoa escreveu e, embaixo de cada campo, o aviso do que falta.
Você está aqui: este é o caminho que uma requisição percorre dentro do app.
flowchart LR
Navegador --> Rota --> Controller
Controller <--> Model
Model <--> Banco[(Banco de dados)]
Controller --> View --> Navegador
classDef aqui fill:#73121b,stroke:#f2b8be,stroke-width:2px,color:#fff
classDef visto fill:#fbe3e5,stroke:#c98b91,color:#490606
class Model,Controller,View aqui
class Rota,Banco visto
Em vermelho escuro, as peças deste capítulo; em rosa claro, as que você já conhece dos capítulos anteriores.
As regras ficam no model
O model Message deixou de ser só o lugar que guarda e busca recados: agora ele também sabe o que é um recado válido. Como todo recado passa pelo model antes de ir para o banco de dados, a regra vale para tudo: o formulário de postar, a correção e até o console.
Quem decide é você
O Rails não tinha como saber que um recado vazio é um problema: para ele, um texto vazio é um texto como outro qualquer. Decidir as regras (o que é obrigatório, qual o tamanho máximo, o que acontece quando algo falta) é trabalho de quem programa. Foi por isso que você pensou nelas no plano, antes de escrever código.
Redirect ou render
Até aqui, depois de guardar, o controller usava o redirect_to: ele manda o navegador fazer uma requisição nova, e a página começa do zero, com o formulário vazio. Agora, quando o recado é recusado, o controller usa o render: ele monta a página na mesma hora, com o @message que acabou de ser recusado. Por isso o que a pessoa escreveu continua no formulário, junto com os avisos.
Não existem perguntas bobas
Por que a regra fica no model, e não na view?
Porque o formulário é só um dos jeitos de criar um recado. Também dá para criar pelo console, pela correção e, num app maior, por outros caminhos. Com a regra no model, todo recado passa por ela, venha de onde vier.
É a ideia de centralizar: a regra fica escrita num lugar só. Se ela estivesse em cada formulário, seria preciso repetir a mesma regra no new.html.erb, no edit.html.erb e em qualquer outra página nova, e bastaria esquecer uma para um recado vazio passar. Com a regra no model, mudar o limite de 280 para 200 caracteres é mudar uma linha, e a mudança vale para o app inteiro.
E os recados vazios que já estavam guardados?
As regras só valem para o que for guardado daqui para frente. Um recado vazio guardado antes continua lá, até alguém apagar. Por isso, no passo 2, você apagou o cartão vazio.
Por que 280 caracteres?
É uma decisão de quem planeja o app: o suficiente para um recado, e pouco o bastante para caber num cartão. O número 280 é só um exemplo, baseado no limite de uma postagem no X (antigo Twitter), um tamanho que muita gente já conhece como mensagem curta. Outro app, ou outro grupo, poderia escolher outro número. O importante é a regra existir e estar escrita num lugar só, o model.
O que é o unprocessable_entity? Para ir além
É o nome de um código de status, um número que o app manda junto com cada página para dizer como foi a requisição. Esse é o 422, que quer dizer “recebi o formulário, mas não deu para usar o que veio nele”. O navegador usa esse código para saber que precisa mostrar a página com os avisos, em vez de seguir em frente.
Por que não aparecem os avisos todos juntos, em cima do formulário? Para ir além
Daria, com o @message.errors.full_messages, mas o Rails monta essas frases juntando o nome da coluna, em inglês, com o aviso: ficaria Author Escreva o seu nome.. Mostrando cada aviso embaixo do seu campo, a pessoa vê só a frase que você escreveu, e já sabe onde corrigir.
Quebre de propósito Opcional
Na ação create, troque a linha render :new, status: :unprocessable_entity por redirect_to new_message_path. Salve, clique em Novo recado, escreva só o seu nome e clique em Postar recado.
Dê um palpite: o que vai acontecer?
A página Novo recado volta, mas vazia: o seu nome sumiu, e nenhum aviso aparece. O redirect_to manda o navegador fazer uma requisição nova, e a ação new prepara um recado em branco, sem nada do que você escreveu e sem os avisos. É por isso que, quando o recado é recusado, o controller usa o render.
Volte a linha para render :new, status: :unprocessable_entity e salve.
Agora, no model, troque presence: { message: "Escreva o seu nome." } por só presence: true. Salve e poste um recado sem nome.
Dê um palpite: o que o aviso vai dizer?
Aparece can't be blank, em inglês: é o aviso que o Rails usa quando você não escreve o seu.
Volte para presence: { message: "Escreva o seu nome." }, salve e poste de novo: o aviso volta para o português.
Preciso de IA para este capítulo?
Não. As regras são poucas linhas no model, e o próprio Rails guarda os avisos de cada campo.
Se quiser usar uma IA, use como tutora: peça para ela explicar, e faça você cada passo. Por exemplo:
Por que as regras de um recado ficam no model, e não no formulário? Me explique sem me dar código.
Veja como começar a conversa em Usando IA como tutora.
E se eu pedisse o código para a IA? Para ir além
Este capítulo é o melhor exemplo do porquê de pensar antes de pedir.
Se você pedir para uma IA “fazer um mural de recados em Rails”, o código gerado pode aceitar recados vazios, como o seu aceitava até agora, ou pode vir com regras que a IA escolheu sozinha, que podem não ser as que você queria. Depende da ferramenta e do pedido. Quem decide que um recado vazio é um erro é você, e a IA só sabe disso se você disser.
Com o plano, o pedido fica assim:
No meu app Rails, o model
Messagetemauthorecontent. Quero estas regras:authorecontentobrigatórios, econtentcom no máximo 280 caracteres. Os avisos devem ser em português: “Escreva o seu nome.”, “Escreva o seu recado.” e “O recado pode ter no máximo 280 caracteres.”. Quando o recado for recusado, o formulário volta com o que a pessoa escreveu e com o aviso embaixo de cada campo.
Confira o resultado contra o plano:
- As três regras estão no model?
- Um recado só com espaços é recusado?
- A ação
createe a açãoupdateconferem se deu certo, comif? - O que a pessoa escreveu continua no formulário quando o recado é recusado?
Veja mais dicas em Como pedir código para uma IA, nos Extras.
Não esqueça
- As regras dos dados ficam no model, com o
validates, e valem para todo recado, venha de onde vier. - O
savee oupdaterespondemtruese deu certo efalsese o recado foi recusado. - Quando dá certo, o controller usa o
redirect_to; quando o recado é recusado, usa orender, que mantém o que a pessoa escreveu. - O Rails não sabe o que é um recado válido: quem decide é quem programa.
Quiz
- Alguém tenta postar um recado só com o nome. O recado é guardado no banco de dados?
- Por que o nome que a pessoa escreveu continua no formulário quando o recado é recusado?
- Você quer que o nome tenha no máximo 50 caracteres. Em qual arquivo você escreve essa regra?
Ver respostas
- Não. O model confere as regras antes de guardar, e o
saverespondefalse. - Porque o controller usa o
render, que mostra a página com o@messagerecusado, em vez doredirect_to, que começaria do zero. - No model,
app/models/message.rb:validates :author, length: { maximum: 50, message: "..." }.
Para saber mais
Guia oficial do Rails, em inglês:
- Active Record Validations: todas as regras que o Rails já traz prontas.
E agora?
O mural de recados está pronto: bonito, e só aceita recados de verdade. Mas ele só funciona dentro do seu codespace. Próximo desafio, opcional: Como mostrar o mural de recados para o mundo?
Vai parar por aqui hoje? Veja como desligar tudo e voltar outro dia em Terminei! E agora?.