Acrescentando um campo num model do Rails
Quando a gente desenvolve uma aplicação, ela cresce e evolui conforme as necessidades dos usuários, da equipe de suporte, e diversos outros fatores. Neste contexto, é comum precisar acrescentar campos aos models que já existem nela.
Neste post vamos acrescentar um campo no model que criamos no post sobre callbacks. Se trata do model que controla os roteiros da operadora de turismo. Tínhamos lhe dado o nome Itinerary. Neste post vamos acrescentar um campo para podermos guardar o endereço de e-mail do cliente que estiver comprando aquele roteiro. O nome do campo novo será customer_email.
Bora?
1 - Escreva o teste (ou atualize um existente)
Para mantermos nossa aplicação saudável, vamos sempre começar pelos testes. Neste momento ainda não temos nenhum teste que simule um usuário criando um roteiro novo na nossa aplicação. Então vamos começar por ele.
Algo assim:
Prontinho! Agora temos um teste para a criação de novos roteiros! Vamos roda-lo para termos certeza de que está tudo em ordem.
Chamamos o comando rspec somente para o arquivo que acabamos de criar, e temos:
Beleza! O teste passou, conforme o previsto.
Agora vamos atualizar o teste, para incluir a nova funcionalidade, que é o email do cliente. Vamos chamar nosso campo de customer_email, então nosso teste deverá ficar desta forma:
Quando rodamos ele novamente, desta vez temos um problema:
Era isso mesmo que a gente queria! Nosso teste está falhando por não encontrar o campo para inserir o e-mail do cliente. Agora é hora de inserir este campo!
Vamos lá!
2 - Crie e rode a migration
Sempre que precisamos alterar qualquer coisa no banco de dados de uma aplicação Rails, nós usamos migrations. Se olharmos
o post sobre o scaffold, veremos que um dos passos do scaffold é a criação da migration que nós rodamos para criar a tabela no banco de dados.
Agora que vamos acrescentar um campo numa tabela existente, vamos criar a migration nós mesmos. Fazemos isso rodando o seguinte comando dentro do diretório da aplicação no terminal:
rails g migration AddCustomerEmailToItinerary customer_email
Neste comando estamos chamando o Rails, usando o "g"- que é abreviação de "generate", pedindo uma migration com o nome AddCustomerEmailToItinerary, e dizendo que o campo a ser adicionado se chama customer_email. Como não especificamos nenhum tipo de dado para customer_email, o Rails vai colocar seu padrão, que é string.
Quando rodamos o comando, vemos que o Rails chama o ActiveRecord e gera o arquivo 20230103171959_add_customer_email_to_itinerary.rb no diretório db/migrate.
Vamos ver o que tem neste arquivo?
Vemos que o Rails usou suas magias para criar um método change que acrescenta uma coluna na tabela itineraries. O nome da nova coluna é customer_email e o tipo de dado é string. Está tudo em ordem, conforme queríamos! Podemos rodar a migration.
Usamos o comando rails db:migrate e temos:
Vemos que deu tudo certo e o Rails criou a coluna.
O que acontece se rodarmos nosso teste agora? Ele continua falhando, porque precisamos colocar este novo campo no formulário.
Bora fazer isso?
3 - Insira o campo no formulário
Depois que o Rails criou a coluna no banco de dados, ainda precisamos colocar o campo no formulário que o usuário preenche. Para fazer isso, vamos até o arquivo app/views/itineraries/_form.html.erb:
Nele vemos que na linha 3 o método form_with abre a criação de um formulário. Os campos subtotal e discount são inseridos nas linhas 18 e 23, respectivamente. Na linha 27 temos o método que gera o botão submit, que para o usuário aparece como "Create Itinerary".
Agora vamos criar o nosso campo, customer_email. Acrescentamos as seguintes linhas:
Veja que o nosso campo é bem semelhante aos outros. Temos uma div com classe "field", um método label com o nome do nosso campo, e um método text_field também com o nome. A única diferença entre este e os outros dois, é que os outros são números, então eles têm number_field ao invés de text_field. Isso é uma mescla de HTML tradicional e o que chamamos de "Rails helpers". Falaremos mais sobre Rails helpers em outros posts.
Colocamos estas linhas antes das linhas do subtotal e nosso arquivo do formulário fica assim:
Vamos rodar nosso teste agora? Será que temos novidades?
Sim! Temos novidades!
Ele ainda está falhando, mas não mais no formulário. Lendo a mensagem da falha, vemos que agora se trata da parte em que o e-mail não aparece na tela que nos diz que o roteiro foi criado.
Bora codar isso?
4 - Acrescente o novo dado na tela de show
Depois que o Rails cria um novo registro, ele mostra os dados deste registro para o usuário. A tela onde isso acontece é chamada de show pelo Rails. Precisamos então da show de itineraries.
Vamos encontra-la em app/views/itineraries/show.html.erb:
Usando o subtotal como exemplo, vemos que ele é construído nas linhas 5 a 8. O Rails cria um p na linha 5, dentro dele coloca a palavra "Subtotal" na linha 6, e o valor do subtotal do roteiro em questão na linha 7.
Para acrescentar nosso novo dado, vamos fazer algo parecido com customer_email:
Inserindo estas linhas logo acima de subtotal no arquivo, temos:
Será que agora está tudo pronto? Vamos rodar nosso teste?
Iiihhh, continua falhando. Mas mudou alguma coisa?
Se olharmos rápido, parece que não, porém mudou sim! Veja que apesar do RSpec não estar encontrando o endereço de e-mail inserido, ele está vendo que a tela agora tem o texto "Customer email:".
O que está acontecendo é que apesar de estar recebendo o valor do campo e-mail, o Rails não está salvando isso no banco de dados. Precisamos do passo final para corrigir isso e finalizar.
Bora?
5 - Permita que o controller receba o novo campo
Quando o usuário clica no botão "Create Itinerary", o Rails manda os dados do formulário para o controller dos roteiros, que é chamado de ItinerariesController.
Podemos encontra-lo em app/controllers/itineraries_controller.rb:
Ele foi criado automaticamente pelas mágicas do Rails na hora do scaffold. Este arquivo é responsável por diversas coisas que podemos aprender em outro post. Neste momento, nosso foco será nas linhas 73 a 75, o método itinerary_params:
Para te ajudar a manter a sua aplicação de forma segura na internet, o Rails te dá esta ajudinha de permitir que somente dados previstos entrem na próxima camada. Neste método o Rails diz que para um dado entrar, ele precisa fazer parte de um itinerary e se chamar subtotal ou discount.
Até agora isso era suficiente, mas neste momento estamos implementando uma nova funcionalidade que é um novo dado. Precisamos que o controller aceite nosso dado novo.
Para isso, vamos acrescenta-lo à lista do método:
O que deixa nosso controller assim:
Será que agora vai?
Bora rodar o teste:
Pronto!
Maravilha! Nosso teste agora passou!
Se rodarmos nossa aplicação, conseguiremos criar roteiros incluindo o endereço de e-mail do cliente!