Mão na massa
Travou em algum passo? Veja Travou?, no fim da página.
Neste capítulo, você vai criar a página Novo recado, com um formulário, e seguir o caminho do recado até ele aparecer no mural de recados. Os erros voltam a aparecer, como em Como ver todos os recados?, e cada um mostra a próxima peça que falta.
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 título Mural de recados e o convite Ainda não tem nenhum recado. Que tal postar o primeiro?, do fim do capítulo anterior.
Terminou? Abra o passo 2. Coloque o link Novo recado na página principal
2. Coloque o link Novo recado na página principal
O recado novo vai ser escrito numa página só para o formulário. Primeiro, a página principal precisa de um caminho até lá: um link.
Abra o app/views/messages/index.html.erb. Logo abaixo do título (a linha do <h1>), acrescente:
<%= link_to "Novo recado", new_message_path %>
Salve o arquivo.
link_tocria um link. O primeiro pedaço é o texto que aparece na página: Novo recado.new_message_pathé o endereço da página do recado novo. É um nome que o Rails cria a partir das rotas, como oroot_path.
Dê um palpite: na aba do app, abra a página principal: o endereço sem nada depois do .app.github.dev, parecido com este:
https://seu-codespace-3000.app.github.dev/
O link vai aparecer?
Confira: ainda não! Aparece a página de erro NameError, com a mensagem undefined local variable or method 'new_message_path'.
O Rails não conhece o new_message_path porque ainda não existe uma rota para a página do recado novo.
Viu o erro? Agora, abra o passo 3. Resolva o erro: crie a rota
3. Resolva o erro: crie a rota
Abra o config/routes.rb. Hoje ele tem esta linha:
get "messages", to: "messages#index"
Troque essa linha por:
resources :messages, only: [ :index, :new ]
Salve o arquivo. Não mexa na linha do root.
resources :messagescria as rotas dos recados seguindo a convenção do Rails: cada ação ganha o seu endereço e o seu tipo de requisição, sem você precisar escrever uma linha para cada uma.only(somente) lista as ações que você quer. Por enquanto, duas:index(ver a lista, comGET /messages, a mesma rota de antes) enew(a página do recado novo, comGET /messages/new).
Recarregue a página.
Confira: a página principal volta, agora com o link Novo recado embaixo do título.
Dê um palpite: clique em Novo recado. O que vai acontecer?
Confira: aparece um erro diferente! Progresso! Agora é a página Unknown action, com a mensagem The action 'new' could not be found for MessagesController.
A rota levou até a ação new do MessagesController, mas o controller ainda não sabe fazer new.
Viu o novo erro? Agora, abra o passo 4. Crie a ação new
4. Crie a ação new
Um formulário precisa saber o que ele vai preencher. No nosso caso, um recado novo, ainda em branco. É a ação new que prepara esse recado.
Abra o app/controllers/messages_controller.rb e acrescente a ação new, logo depois do index:
class MessagesController < ApplicationController
def index
@messages = Message.order(created_at: :desc)
end
def new
@message = Message.new
end
end
Salve o arquivo.
Message.newcria um recado novo, em branco, só na memória do app. Ele não é guardado no banco de dados. É diferente doMessage.createque você usou no console, que cria e já guarda.@message(no singular) é o recado em branco do formulário.@messages(no plural) continua sendo a lista de recados. Repare na diferença de uma letra.
Dê um palpite: recarregue a página. E agora?
Confira: mais um erro! É a página No view template for interactive request, com a mensagem MessagesController#new is missing a template for request formats: text/html. Quer dizer: a ação new existe, mas não tem uma view para mostrar.
Leia o resto da mensagem: o próprio Rails diz onde ele procurou a view, em app/views/messages/new.html.erb. No capítulo anterior, quem criou a view do index foi o gerador. Agora, você vai criar a view à mão.
Viu o erro? Agora, abra o passo 5. Crie a página do formulário
5. Crie a página do formulário
No Explorer, clique com o botão direito na pasta app/views/messages, escolha New File… e crie o arquivo new.html.erb. Escreva nele:
<h1>Novo recado</h1>
<%= form_with model: @message do |form| %>
<div>
<%= form.label :author, "Seu nome" %>
<%= form.text_field :author %>
</div>
<div>
<%= form.label :content, "Recado" %>
<%= form.text_area :content %>
</div>
<%= form.submit "Postar recado" %>
<% end %>
<%= link_to "Voltar", root_path %>
Salve o arquivo.
form_with model: @messagecria um formulário para o recado em branco que a açãonewpreparou.form.labelé o texto que aparece ao lado de cada campo: Seu nome e Recado.form.text_field :authoré uma caixa de texto de uma linha só, para a autora.form.text_area :contenté uma caixa maior, para a mensagem.form.submité o botão que envia o formulário.link_to "Voltar", root_pathé um link de volta para a página principal.
Dê um palpite: recarregue a página. Como o formulário vai aparecer?
Confira: aparecem o título Novo recado, os campos Seu nome e Recado, o botão Postar recado e o link Voltar, ainda sem nenhum enfeite. O visual fica para outro capítulo.
Clique em Voltar e depois em Novo recado de novo, para ver o caminho entre as duas páginas.
Terminou? Abra o passo 6. Poste o primeiro recado
6. Poste o primeiro recado
Na página Novo recado, preencha o formulário:
- Seu nome: Ana
- Recado: Meu primeiro recado!
Clique em Postar recado.
Dê um palpite: o recado vai aparecer no mural de recados?
Confira: ainda não! E, desta vez, na tela não acontece nada: a página Novo recado continua igual. Quando um formulário dá erro, o Rails não mostra a página de erro no navegador. O erro aparece em outro lugar: no terminal do servidor.
Vá até o terminal onde está rodando o bin/rails server e olhe as últimas linhas. Lá aparece:
Started POST "/messages"
ActionController::RoutingError (No route matches [POST] "/messages"):
Guarde esta dica para o resto do projeto: clicou e nada aconteceu? Olhe o terminal do servidor. É lá que o app conta o que deu errado.
Repare no POST. Até agora, o navegador só fazia requisições do tipo GET, que servem para pedir uma página. Para enviar um formulário, ele usa o POST. E as rotas que você criou só recebem GET.
Viu o erro no terminal? Agora, abra o passo 7. Resolva o erro: complete a rota
7. Resolva o erro: complete a rota
Abra o config/routes.rb e acrescente o :create na lista do only:
resources :messages, only: [ :index, :new, :create ]
Salve o arquivo.
create(criar) é a ação que recebe o formulário, comPOST /messages, a rota que faltava.
Dê um palpite: a rota para o POST agora existe. Volte para a página Novo recado, preencha o formulário de novo e clique em Postar recado. O que vai aparecer no terminal do servidor?
Viu o novo erro no terminal? Agora, abra o passo 8. Ah não! Um novo erro!
8. Ah não! Um novo erro!
Confira: de novo, nada acontece na tela. Olhe o terminal do servidor: aparece um erro diferente! Progresso!
AbstractController::ActionNotFound (The action 'create' could not be found for MessagesController):
A rota mandou o formulário para a ação create do MessagesController, mas o controller ainda não sabe fazer create.
Abra o app/controllers/messages_controller.rb e deixe o arquivo assim:
class MessagesController < ApplicationController
def index
@messages = Message.order(created_at: :desc)
end
def new
@message = Message.new
end
def create
Message.create(message_params)
redirect_to root_path
end
private
def message_params
params.expect(message: [ :author, :content ])
end
end
Salve o arquivo. Tem bastante coisa nova aqui:
def createé a ação que recebe o formulário.Message.create(message_params)cria o recado com o que veio do formulário e guarda no banco de dados, como oMessage.createdo console.redirect_to root_pathmanda o navegador de volta para a página principal, que mostra o mural de recados com o recado novo.privatesepara as ações das partes que só o controller usa por dentro. Tudo que vem depois dele não é uma ação.message_paramsé a lista do que o controller aceita do formulário: um recado (message) com autora (author) e mensagem (content). Qualquer outra informação que chegar é ignorada.
Dê um palpite: volte para a página Novo recado, preencha o formulário e clique em Postar recado. E agora?
Confira: no Codespaces, nada acontece na tela, mais uma vez. Olhe o terminal do servidor: aparece um erro novo, parecido com este:
ActionController::InvalidAuthenticityToken (HTTP Origin header (https://localhost:3000) didn't match request.base_url (https://seu-codespace-3000.app.github.dev)):
A rota e a ação já existem. Agora quem recusou o formulário foi uma proteção do Rails. É o assunto do próximo passo.
Está usando o seu próprio computador, e não o Codespaces? Para você, o recado já aparece no mural de recados. Pule o próximo passo e siga para o passo 10. E se o recado vier vazio?
Viu o erro no terminal? Agora, abra o passo 9. Mais um erro: a proteção de formulários
9. Mais um erro: a proteção de formulários
O Rails tem uma proteção que confere se um formulário veio do próprio app, e não de outro site. Leia o erro de novo: o endereço de origem do formulário (localhost:3000) não bate com o endereço do app (o .app.github.dev). No Codespaces, os dois endereços são diferentes, e essa proteção acaba recusando os formulários do próprio app.
No Explorer, abra o arquivo config/environments/development.rb. Logo antes do último end, acrescente esta linha:
config.action_controller.forgery_protection_origin_check = false
Salve o arquivo.
Essa linha desliga só a conferência do endereço de origem, e só enquanto você desenvolve o app (development, em inglês). A proteção continua funcionando no app publicado.
Esse arquivo só é lido quando o servidor liga. Então, reinicie o servidor: no terminal do servidor, aperte Ctrl+C para desligar e, depois, ligue de novo:
bin/rails server
Dê um palpite: volte para a página Novo recado, preencha o formulário e clique em Postar recado. E agora?
Confira: o navegador volta para a página principal, e o recado da Ana aparece no mural de recados! 🎉 O convite sumiu.
Poste mais um, para ver a ordem. Clique em Novo recado e preencha:
- Seu nome: Bia
- Recado: Adorei o workshop!
Confira: o recado da Bia aparece em cima do da Ana, porque é o mais novo.
Terminou? Abra o passo 10. E se o recado vier vazio?
10. E se o recado vier vazio?
Dê um palpite: o que acontece se alguém clicar em Postar recado sem escrever nada?
Teste: clique em Novo recado, deixe os dois campos vazios e clique em Postar recado.
Confira: nenhum erro aparece, e o mural de recados ganha um recado vazio: só um travessão (—), sem mensagem e sem autora.
Você já tinha visto isso no “Quebre de propósito” de Como guardar os recados?: o Rails guarda o recado porque ninguém disse a ele que um recado vazio é proibido. Decidir isso é trabalho de quem programa, e é o assunto do capítulo E se alguém mandar um recado vazio?.
Por enquanto, apague o recado vazio pelo console. No terminal novo:
bin/rails console
Message.last.destroy
Esse comando pega o último recado guardado e apaga, como no capítulo 02. Depois, saia do console. Digite:
exit
Recarregue a página.
Confira: o recado vazio sumiu, e os recados da Bia e da Ana continuam lá.
Terminou? Abra o passo 11. Guarde o seu progresso
11. 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
Posta recados pelo formulárioe clique em Commit. - Clique em Sync Changes e, na janela que abrir, em OK.
Confira: em Graph, o commit Posta recados pelo formulário aparece com a etiqueta main e o ícone de nuvem.
Travou?
Abra o problema que aconteceu com você:
A página continua mostrando o erro, mesmo depois de corrigir
Confira se você salvou todos os arquivos: no editor, um arquivo com mudanças não salvas tem uma bolinha no lugar do X, na aba. Salve (Cmd+S ou Ctrl+S) e recarregue a página.
Aparece Passed nil to the :model argument
O formulário não recebeu o recado em branco. Confira se o controller tem a linha @message = Message.new dentro do def new (passo 4), com o @ e no singular.
Aparece InvalidAuthenticityToken ou HTTP Origin header didn't match
É a proteção de formulários do passo 9. Confira se a linha config.action_controller.forgery_protection_origin_check = false está no config/environments/development.rb, antes do último end, e se você reiniciou o servidor depois de salvar (Ctrl+C e bin/rails server). Se continuar, peça ajuda para alguém da mentoria. 💜
A ação new ou create existe, mas continua aparecendo could not be found
Confira se o def new e o def create estão antes da linha private. Tudo que vem depois do private não é uma ação, e o Rails não encontra.
Aparece param is missing or the value is empty
O controller não encontrou o recado no que veio do formulário. Confira se o new.html.erb usa form_with model: @message e se os campos se chamam :author e :content, iguais aos do message_params.
Cliquei em Postar recado e nada aconteceu
Primeiro, olhe o terminal do servidor: quando um formulário dá erro, é lá que o erro aparece, e não no navegador. Leia a última linha de erro e compare com os passos 6, 8 e 9.
Se não tiver erro no terminal, clique em Voltar: se o recado aparecer, ele foi guardado, mas o navegador não voltou para o mural de recados. Confira se a ação create tem a linha redirect_to root_path.
Mentoria: veja as notas deste capítulo.
Terminou?
Siga para O que aconteceu? e entenda cada passo.