Mão na massa
Travou em algum passo? Veja Travou?, no fim da página.
Neste capítulo, você vai escrever as regras de um recado e fazer o app avisar a pessoa quando alguma regra não for cumprida.
1. Ligue o servidor
Abra o seu codespace e ligue o servidor, se ele ainda não estiver ligado:
bin/rails server
Abra o app no navegador (pelo aviso Open in Browser ou pela aba Ports) e deixe essa aba aberta. Para os outros comandos, abra um terminal novo pelo botão +.
Confira: o navegador mostra o mural de recados, com o botão Novo recado e os cartões amarelos.
Terminou? Abra o passo 2. Veja o problema de novo
2. Veja o problema de novo
Clique em Novo recado, deixe os dois campos vazios e clique em Postar recado.
Dê um palpite: o que vai aparecer?
Confira: um cartão vazio, só com o travessão (—). O app aceitou um recado sem nome e sem mensagem.

Apague esse cartão pelo botão Apagar. Ele foi feito no capítulo 05 justamente para isso.
Terminou? Abra o passo 3. Escreva as regras do recado
3. Escreva as regras do recado
As regras sobre os dados ficam no model. Abra o arquivo app/models/message.rb. Ele tem só duas linhas:
class Message < ApplicationRecord
end
Deixe o arquivo assim:
class Message < ApplicationRecord
validates :author, presence: { message: "Escreva o seu nome." }
validates :content, presence: { message: "Escreva o seu recado." }
end
Salve o arquivo.
validates(valida) cria uma regra, que quem programa chama de validação.:authore:contentsão as colunas que a regra confere: a autora e a mensagem.presence(presença) quer dizer que a informação precisa estar lá. Um texto vazio, ou só com espaços, não conta.messageé o aviso que a pessoa vai ver quando a regra não for cumprida.
Terminou? Abra o passo 4. Teste no navegador
4. Teste no navegador
Volte para a aba do app, clique em Novo recado, deixe os dois campos vazios e clique em Postar recado.
Dê um palpite: o cartão vazio vai aparecer?
Confira: não aparece. O model recusou o recado, e nada foi guardado. Mas repare: também não aparece nenhum aviso. O app só volta para o mural de recados, como estava, e quem tentou postar não sabe o que aconteceu.
Veja como fica na tela

Terminou? Abra o passo 5. Veja os avisos no console
5. Veja os avisos no console
Se o app recusou o recado, onde estão os avisos? Vamos perguntar ao model, pelo console.
No terminal novo, abra o console:
bin/rails console
Crie um recado em branco, sem guardar, e pergunte se ele é válido:
recado = Message.new
recado.valid?
Confira: o console responde false (falso): o recado não cumpre as regras. Agora pergunte quais avisos ele tem, um de cada vez. Primeiro, o aviso da autora:
recado.errors[:author]
Confira: o console responde ["Escreva o seu nome."].
Depois, o aviso da mensagem:
recado.errors[:content]
Confira: o console responde ["Escreva o seu recado."].
Saia do console. Digite:
exit
Os avisos existem: o model sabe o que falta. Então por que eles não apareceram no navegador?
O problema está no controller. Abra o app/controllers/messages_controller.rb e olhe a ação create:
def create
Message.create(message_params)
redirect_to root_path
end
Ela tenta guardar o recado e, dando certo ou não, manda o navegador de volta para a página principal. Ninguém confere se o recado foi guardado. É esse o erro: quando o model recusa o recado, a ação create precisa mostrar o formulário de novo, com os avisos, e não voltar para o mural de recados como se tudo tivesse dado certo. É o que você vai arrumar no próximo passo.
Terminou? Abra o passo 6. Confira se o recado foi guardado
6. Confira se o recado foi guardado
No app/controllers/messages_controller.rb, troque a ação create por:
def create
@message = Message.new(message_params)
if @message.save
redirect_to root_path
else
render :new, status: :unprocessable_entity
end
end
Salve o arquivo. Leia com calma, de cima para baixo:
Message.new(message_params)monta o recado com o que veio do formulário, ainda sem guardar.@message.savetenta guardar. Ele respondetrue(verdadeiro) se o recado cumpre as regras e foi guardado, efalse(falso) se não.ifeelsequerem dizer “se” e “senão”. Se guardou, volta para a página principal, como antes. Senão, mostra a página Novo recado de novo, com o recado recusado no formulário.render :newmostra a viewnewsem fazer uma requisição nova. Por isso, o que a pessoa escreveu continua no formulário.status: :unprocessable_entityavisa o navegador que o formulário foi recusado.
Dê um palpite: clique em Novo recado, escreva só o seu nome, deixe o recado vazio e clique em Postar recado. O seu nome continua no formulário?
Confira: continua! A página Novo recado fica aberta, com o nome no campo, e nenhum cartão vazio é guardado. Mas o aviso ainda não aparece: falta a view mostrar.
Terminou? Abra o passo 7. Mostre o que falta
7. Mostre o que falta
Abra o app/views/messages/new.html.erb. No formulário, logo abaixo da linha do form.text_field :author, acrescente:
<% @message.errors[:author].each do |error| %>
<p class="help is-danger"><%= error %></p>
<% end %>
E logo abaixo da linha do form.text_area :content, acrescente:
<% @message.errors[:content].each do |error| %>
<p class="help is-danger"><%= error %></p>
<% end %>
O formulário fica assim:
<%= form_with model: @message, class: "box" do |form| %>
<div class="field">
<%= form.label :author, "Seu nome", class: "label" %>
<%= form.text_field :author, class: "input" %>
<% @message.errors[:author].each do |error| %>
<p class="help is-danger"><%= error %></p>
<% end %>
</div>
<div class="field">
<%= form.label :content, "Recado", class: "label" %>
<%= form.text_area :content, class: "textarea" %>
<% @message.errors[:content].each do |error| %>
<p class="help is-danger"><%= error %></p>
<% end %>
</div>
<%= form.submit "Postar recado", class: "button is-primary" %>
<% end %>
Salve o arquivo.
@message.errors[:author]é a lista de avisos da autora, a mesma que você viu no console. Oeachmostra cada aviso.help is-dangeré do Bulma: um texto pequeno, em vermelho, embaixo do campo.- Quando o formulário aparece pela primeira vez, o recado em branco ainda não foi conferido, então não tem aviso nenhum.
Dê um palpite: deixe os dois campos vazios e clique em Postar recado. O que aparece?
Confira: embaixo de cada campo, em vermelho, aparece o que falta:

Agora preencha os dois campos e poste: o recado aparece normalmente. 🎉
Terminou? Abra o passo 8. E um recado enorme?
8. E um recado enorme?
Um post-it não cabe um livro. O nosso plano limita a mensagem a 280 caracteres.
No app/models/message.rb, acrescente mais uma regra, logo abaixo das outras:
validates :content, length: { maximum: 280, message: "O recado pode ter no máximo 280 caracteres." }
O model fica assim:
class Message < ApplicationRecord
validates :author, presence: { message: "Escreva o seu nome." }
validates :content, presence: { message: "Escreva o seu recado." }
validates :content, length: { maximum: 280, message: "O recado pode ter no máximo 280 caracteres." }
end
Salve o arquivo.
length(comprimento) confere o tamanho do texto.maximum: 280quer dizer “no máximo 280 caracteres”. Letras, espaços e emojis contam.
Digitar 281 caracteres no formulário daria trabalho. Então teste no console:
bin/rails console
recado = Message.new(author: "Ana", content: "a" * 281)
recado.valid?
O "a" * 281 monta um texto com a letra “a” repetida 281 vezes.
Confira: o valid? responde false. Agora veja o aviso:
recado.errors[:content]
Confira: o console mostra ["O recado pode ter no máximo 280 caracteres."]. Troque o 281 por 280 e teste de novo: agora o recado é válido.
Saia do console com exit.
Terminou? Abra o passo 9. E na correção?
9. E na correção?
Dê um palpite: clique em Editar num recado, apague a mensagem e clique em Salvar. O que vai acontecer?
Confira: você volta para o mural de recados, e o recado continua com a mensagem antiga. A regra funcionou, e a mensagem vazia não foi guardada. Mas, de novo, ninguém avisou a pessoa: parece que a correção foi ignorada.
É o mesmo problema dos passos 4 e 5, agora na ação update. No app/controllers/messages_controller.rb, troque a ação update por:
def update
@message = Message.find(params[:id])
if @message.update(message_params)
redirect_to root_path
else
render :edit, status: :unprocessable_entity
end
end
O @message.update também responde true ou false, como o save. Se der errado, a página de correção aparece de novo, com o que a pessoa escreveu.
Agora a página de correção precisa mostrar os avisos, como a página Novo recado. Abra o app/views/messages/edit.html.erb e deixe o arquivo assim:
<section class="section">
<div class="container">
<h1 class="title">Corrigir recado</h1>
<%= form_with model: @message, class: "box" do |form| %>
<div class="field">
<%= form.label :author, "Seu nome", class: "label" %>
<%= form.text_field :author, class: "input" %>
<% @message.errors[:author].each do |error| %>
<p class="help is-danger"><%= error %></p>
<% end %>
</div>
<div class="field">
<%= form.label :content, "Recado", class: "label" %>
<%= form.text_area :content, class: "textarea" %>
<% @message.errors[:content].each do |error| %>
<p class="help is-danger"><%= error %></p>
<% end %>
</div>
<%= form.submit "Salvar", class: "button is-primary" %>
<% end %>
<%= link_to "Voltar", root_path %>
</div>
</section>
Salve os dois arquivos.
Confira: abra a correção de um recado, apague a mensagem e clique em Salvar. Aparece o aviso Escreva o seu recado. embaixo do campo, e o recado não muda até você escrever alguma coisa.
Repare: o formulário do edit.html.erb é igual ao do new.html.erb, com os mesmos avisos. Só mudam o título e o texto do botão.
Um formulário só para as duas páginas Para ir além
Você escreveu o mesmo formulário duas vezes. Se um dia o recado ganhar um campo novo, como a cor do desafio extra, vai ser preciso mexer nos dois arquivos, e é fácil esquecer um deles. O Rails tem um jeito de escrever um pedaço de view uma vez só e usar em várias páginas: a partial.
1. No Explorer, clique com o botão direito na pasta app/views/messages, escolha New File… e crie o arquivo _form.html.erb. O _ no começo do nome é o que diz ao Rails que o arquivo é uma partial. Escreva nele:
<%= form_with model: message, class: "box" do |form| %>
<div class="field">
<%= form.label :author, "Seu nome", class: "label" %>
<%= form.text_field :author, class: "input" %>
<% message.errors[:author].each do |error| %>
<p class="help is-danger"><%= error %></p>
<% end %>
</div>
<div class="field">
<%= form.label :content, "Recado", class: "label" %>
<%= form.text_area :content, class: "textarea" %>
<% message.errors[:content].each do |error| %>
<p class="help is-danger"><%= error %></p>
<% end %>
</div>
<%= form.submit submit_text, class: "button is-primary" %>
<% end %>
É o mesmo formulário, com duas diferenças: o recado se chama message, sem o @, e o texto do botão é o submit_text (texto do botão). Quem usa a partial é que diz o que vai em cada um.
2. Deixe o app/views/messages/new.html.erb assim:
<section class="section">
<div class="container">
<h1 class="title">Novo recado</h1>
<%= render "form", message: @message, submit_text: "Postar recado" %>
<%= link_to "Voltar", root_path %>
</div>
</section>
3. E o app/views/messages/edit.html.erb assim:
<section class="section">
<div class="container">
<h1 class="title">Corrigir recado</h1>
<%= render "form", message: @message, submit_text: "Salvar" %>
<%= link_to "Voltar", root_path %>
</div>
</section>
Salve os três arquivos.
render "form"coloca a partial_form.html.erbnaquele lugar da página. Norender, o nome vai sem o_e sem o.html.erb.message: @messageentrega o recado para a partial, esubmit_text:entrega o texto do botão.
Confira: abra a página Novo recado e a correção de um recado. As duas aparecem iguais a antes, com os avisos quando falta alguma coisa. A diferença está no código: o formulário agora mora num lugar só.
Terminou? Abra o passo 10. Guarde o seu progresso
10. Guarde o seu progresso
Guarde o seu progresso com um commit, como no passo Guarde o seu progresso de Por onde começar?:
- No painel Source Control, clique no + ao lado de Changes (Stage All Changes).
- Escreva a mensagem
Valida os recados e mostra os avisose clique em Commit. - Clique em Sync Changes e, na janela que abrir, em OK.
Confira: em Graph, o commit Valida os recados e mostra os avisos aparece com a etiqueta main e o ícone de nuvem.
Travou?
Abra o problema que aconteceu com você:
A página continua aceitando o recado vazio
Confira se o app/models/message.rb está salvo e se cada validates está dentro da class, antes do end. Confira também se os nomes das colunas estão certos: :author e :content.
Cliquei em Postar recado e nada aconteceu, nem o aviso
Confira se o render :new tem o status: :unprocessable_entity no fim. Sem ele, o navegador não mostra a página com o aviso. Depois, confira se a view tem os blocos do @message.errors do passo 7.
O aviso aparece em inglês, como can't be blank
Falta o message: na regra, no model. Confira se cada validates está igual ao do passo 3, com o aviso entre aspas.
Aparece um erro de sintaxe depois de mudar o controller
Confira se cada if tem o seu end, e se cada def também. Na ação create, são dois end no fim: um do if e um do def. Compare com o código do passo 6. Na dúvida, peça ajuda para alguém da mentoria. 💜
Mentoria: veja as notas deste capítulo.
Terminou?
Siga para O que aconteceu? e entenda cada passo.