loading...
Cover image for CRUD em Ruby on Rails

CRUD em Ruby on Rails

jackson541 profile image Jackson Alves ・10 min read

Olá, dev! Hoje estaremos dando continuidade ao projeto de lista de tarefas que iniciamos no último post, dessa vez fazendo o famoso CRUD (Create, Read, Update, Delete) da nossa aplicação.

Se você caiu aqui de paraquedas, não se preocupe! Basta já ter um projeto criado em Rails, ou ver o primeiro post para criar um, que já poderá continuar.

Caso fique com dúvida sobre como fazer algo durante a explicação, pode acessar esse repositório que contém todo o código desenvolvido nesse artigo.

Está pronto!? Então abra o editor, rode o projeto e prepare o café!

Para ir até a página inicial do site, execute o comando na página do projeto:

rails server

E acesse a url http://localhost:3000 Se tudo ocorreu bem, você deve encontrar uma página como essa:
imagem inicial rails

Bom, agora já podemos começar a codar de verdade! Primeiro, temos que criar um Controller para a nossa aplicação, neste caso irei criar um para as listas. Lembre-se que os Controllers são responsáveis por intermediar a comunicação entre a View e a Model no model MVC e também pelas regras de negócio da aplicação.

Rode o seguinte comando para criar um controller:

rails generate controller Listas index

Repare que rails generate controller é o comando padrão para criação de um controller, Listas é seu o nome e index é o método que virá criado dentro dele. Esse último parâmetro, o do método, é opcional, mas ele nos dá algumas vantagens quando preenchido:

  • cria um arquivo nomeado index.html.erb, dentro da pasta /app/views/listas/, que nos servirá para criar o html desse método index;
  • cria a rota /listas/index com o método GET para a nossa aplicação, a declaração dessa rota pode ser vista dentro do arquivo /config/routes.rb

Que tal já começar a escrever algo na tela? Vá até o arquivo index.html.erb que comentei e troque o seu conteúdo para

<h1>Aqui ficarão as nossas listas</h1>

E basta salvar as alterações e acessar a rota http://localhost:3000/listas/index que irá encontrar uma página como essa:
página inicial listas

Excelente, já conseguimos imprimir algo em nosso site! Mas antes de continuarmos, preciso falar sobre algumas dúvidas que você possa estar tendo:

Porque o arquivo html do index termina com .erb?

ERB é um sistema do próprio Ruby que nos permite utilizar códigos dessa linguagem dentro do HTML, sem essa extensão não será possível utilizar código Ruby dentro dos arquivos. Veremos mais sobre isso mais a frente.

Como ele sabe qual arquivo html chamar?

Como ainda não tem nenhum códido dentro do método index no listas_controller.rb, então o Rails presume que ele deve renderizar a view que comece o mesmo nome do método, nesse caso index.

Como funciona a declaração das rotas?

Todas as rotas são declaradas dentro do arquivo routes.rb que está na pasta config. Em geral, basta colocar o nome do método seguido da sua url, como podemos ver em get 'listas/index', em declarações simples como essa o Rails já presume que essa url deve chamar o método index do controller listas. No entanto, podemos definir qual método o Rails irá chamar com uma rota por meio do parâmetro to, exemplo:

get 'listas/minhaslistas', to: 'listas#index'

Nesse caso, o Rails irá chamar o método index do controller listas quando a url http://localhost:3000/listas/minhaslistas for acessada.

Posso colocar esse arquivo html para a rota raiz do site /?

Sim, isso é realmente fácil! Vá até o arquivo routes.rb e digite

root 'controller#metodo'

No nosso caso estarei trocando o controller e o método por

root 'listas#index'

Agora, se você acessar http://localhost:3000 verá que a página do método index também está sendo renderizada na rota raiz. Lembrando que isso serve para qualquer controller que você tiver criado!

E então, ficou com mais alguma dúvida? Ficarei feliz em te responder se deixar elas lá nos comentários!

Criando as rotas

Já sabemos como é fácil criar novos controllers, então precisamos ver bem como criar rotas para acessá-los. Anteriormente, falei que as rotas podem ser definidas utilizando o método de requisição e um comando para apontar o seu controller, porém, o Rails fornece algo que facilita muito a nossa vida quando se trata de rotas ligadas ao CRUD: podemos, com um único comando, definir todas as rotas necessárias para isso.

Vá até o seu routes.rb, abaixo do comando do root, e digite o seguinte:

resources :listas

O seu arquivo deve estar parecido com esse:

Rails.application.routes.draw do
  root 'listas#index' 

  resources :listas

  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

Com essa única linha já definimos todas as rotas para criar, ver, atualizar e deletar relacionadas ao controller listas. Quer ver isso melhor? Então vá até o seu terminal e digite esse comando para listar todas rotas:

rails routes

Você verá uma tabela que lista tudo das rotas: nome, URI, Pattern e o seu controller#action.

rotas do projeto

Essa rotas já serão suficientes para nós nesse projeto, mas, caso queira entender mais a fundo sobre esse ponto no Rails, recomendo olhar a documentação oficial.

Criando a model

Agora precisamos trabalhar com o banco de dados(DB), onde iremos guardar as informações das nossas listas. Para isso, existem as models que nos permitem criar classes que irão representar tabelas no DB.

Para as nossas listas, pensei em colocarmos apenas dois campos simples: nome e descrição. O primeiro é do tipo string e o segundo do tipo text, caso queira adicionar outros, consulte os tipos aceitos pelo Rails. Tudo isso pode ser feito direto pelo terminal:

rails generate model Lista nome:string descricao:text

Repare que Lista é o nome do nosso modelo e os demais são os seus atributos acompanhados dos seus tipos.

Você deve ter recebido uma resposta como essa:

criação model rails

Primeiro, note que ele gerou um arquivo dentro da pasta /db/migrate/, esse arquivo é uma migration. Segundo, o Rails criou um arquivo listum.rb dentro de /app/models/ que é o nosso arquivo de model de fato. Porém, algo engraçado é que ele o criou com o nome Listum em vez de Lista, isso ocorre porque o Rails tenta automaticamente colocar o nome do modelo no plural, o que não acabou dando muito certo nesse caso hahaha. Isso pode acabar nos atrapalhando em algum ponto posterior, então vamos alterar o nome desse arquivo para lista.rb e trocar a sua primeira linha para class Lista < ApplicationRecord.

Analise a migration criada, ela apresenta uma estrutura que representa uma tabela com nome lista e que tem duas colunas: nome e descricao.

class CreateLista < ActiveRecord::Migration[6.0]
  def change
    create_table :lista do |t|
      t.string :nome
      t.text :descricao

      t.timestamps
    end
  end
end

Mas criar uma model não cria a tabela automaticamente no DB, já que podemos querer fazer alguma alteração na migration após essa criação. Sendo assim, precisamos fazer essas mudanças se refletirem no banco de dados e isso é feito com o seguinte comando:

rails db:migrate

Você vai encontrar uma saída como essa informando que a tabela foi criada:
Criação tabela rails

Caso fique com dúvidas sobre os comandos de db do rails, pode acessar esse link da documentação.

Agora sim, caro dev, demos passos importantes no nosso projeto e daremos alguns ainda mais a partir de agora. Chegou a hora de criarmos novos métodos no nosso controller, que tal começarmos pelo de cadastrar uma nova lista?

Criação de novos métodos

Para isso, vamos utilizar duas rotas que já criamos, a /listas/new e a /listas com o método POST. Lembre-se que você pode ver todas as rotas do app utilizando o comando rails routes.

Iniciaremos criando a função new no controller:

class ListasController < ApplicationController
  def index
  end

  def new
  end
end

Por enquanto ele ficará vazio, pois queremos apenas que ele renderize a view padrão.

Em seguida, criamos um arquivo new.html.erb dentro da /views/listas/ e podemos colocar um html qualquer:

<h1>Criar uma nova lista</h1>

Se tudo estiver correto, você conseguirá encontrar esse conteúdo pela rota /listas/new.

Infelizmente apenas esse h1 não irá fazer o cadastro das listas que precisamos haha. Então, vamos complementar a página com um formulário, mas repare que ele terá uma estrutura diferente, a estrutura de tags do Rails:

<h1>Criar uma nova lista</h1>

<%= form_with scope: :lista, local: true, url: listas_path do |form| %>
    <p>
        <%= form.label :nome %>
        <%= form.text_field :nome %>
    </p>
    <p>
        <%= form.label(:descricao, "Descrição") %>
        <%= form.text_area :descricao %>
    </p>
    <p>
        <%= form.submit("Salvar") %>
    </p>
<% end %>

As tags do Rails sempre seguem a estrututa <%= %> e quando é apenas código ruby utiliza-se o <% %>, como no caso do end.

Bom, tenho algumas coisas importantes para te apresentar, então preste atenção! form_with é a tag de formulário que estamos utilizando, nesse caso ela recebe dois parâmetros: o scope que serve para definir um identificador para esse formulário, passamos :lista como identificador, e que será utilizado mais tarde para recuperar os dados preenchidos nos campos. Além desse, também tem o local, que serve para dizer que não queremos enviar as respostas desse form por Ajax.

Existe também um terceiro parâmetro que merece atenção especial, o url. Se ele não fosse passado, os dados seriam enviados para a mesma rota /listas/new, mas com o método POST. Porém, isso não nos serve porque já temos a rota /listas com o POST para receber esses dados, então utilizamos esse parâmetro para definir o novo ponto de envio. Você pode estar se perguntando o que significa listas_path, listas é o nome da rota desejada e quando utilizado o _path o Rails retorna a rota relativa a esse nome, no caso /listas. Lembre-se mais uma vez que tudo sobre as rotas do app podem ser vistas com o comando rails routes.

Agora repare nas demais tags utilizadas:

  • form.label imprime o nome de um campo para o usuário;
  • form.text_field cria um campo de texto comum;
  • form.text_area cria um campo de texto em área;
  • form.submit cria um botão para enviar os dados do form.

Ao recarregar a página você irá encontrar algo assim:
tela formulário lista

O coitado está muito feio, mas isso pode ser resolvido com um pouco de CSS mais tarde.

E ae, já tentou enviar esse fomulário? Se sim, deve ter recebido um erro como esse:

tela erro envio form

Basicamente ele está nos dizendo que não conseguiu encontrar a ação create no controller listas. O que significa que ele está enviando os dados para o local correto, basta criarmos esse método.

def create
    render plain: params.require(:lista).inspect
end

Aqui estamos basicamente inspecionando todos os parâmetros passados, render renderiza um template e plain diz que o template é simplesmente o texto apartir dele. :lista é aquele mesmo identificador que utilizamos no scope do form.

renderizando textos da requisição

Finalmente podemos pegar esses dados e salvá-los no banco de dados. Em tese isso já deveria funcionar:

def create
    @lista = Lista.new(params[:lista])
end

OBS: o Rails sabe que deve chamar o model que criamos pelo nome que utilizamos com a inicial maiúscula, o Lista.

No entanto, se tentarmos enviar novamente o formulário, encontraremos mais um erro:

erro permição parâmetros

Isso ocorreu porque o Rails não nos permite simplesmente pegar todos os atributos passados na requisição do form e salvar, pois um usuário com má intenção pode enviar atributos a mais para quebrar ou roubar algo da nossa aplicação. Sendo assim, precisamos especificar exatamente quais atributos queremos pegar:

def create
    @lista = Lista.new(params.require(:lista).permit(:nome, :descricao))

    @lista.save

    redirect_to lista_path(@lista)
end

Agora estamos pegando apenas o nome e descrição para criar uma nova lista. Já te adiantando, o @lista.save salva a lista no DB e o redirect_to lista_path(@lista) diz ao Rails que queremos redirecionar para o método show e exibir essa nova lista, será que isso vai funcionar?

Infelizmente não! Ainda precisamos criar esse método para que tudo funcione:

def show
    @lista = Lista.find(params[:id])
end

O find irá buscar por uma lista utilizando o seu id, não se preocupe que o Rails irá passar esse id automaticamente pelo comando do redirect_to. Mas antes precisamos criar uma página HTML para renderizar essa lista, então crie um show.html.erb na pasta de listas.

<p>
    <strong>Nome: </strong>
    <%= @lista.nome %>
</p>
<p>
    <strong>Descrição: </strong>
    <%= @lista.descricao %>
</p>

A variável @lista é a mesma que estamos retornando no método show. Então, teremos algo assim:

exibindo uma lista rails

Agora sim! Já conseguimos cadastrar e exibir uma lista, para fechar com chave de ouro vamos exibir todas as listas!

Volte a ação index no controller:

def index
    @listas = Lista.all
end

Dessa forma, a variável listas irá guardar todas as listas registradas, basta exibir elas em seu respectivo arquivo, o index.html.erb:

<h1>Aqui ficarão as nossas listas</h1>

<table>
    <tr>
        <th>Nome</th>
        <th>Descrição</th>
    </tr>

    <% @listas.each do |lista| %>
        <tr>
            <td><%= lista.nome %></td>
            <td><%= lista.descricao %></td>
        </tr>
    <% end %>
</table>

E esse será o nosso resultado:

exibindo todas as listas rails

Conseguimos caminhar bastante! Porém, ainda a muita estrada pela frente, pois o nosso CRUD não está finalizado. Sendo assim, peço que me acompanhe no próximo post dessa jornada!

Discussion

pic
Editor guide