Ruby on Rails Fullstack

Ruby on Rails

Sua doutrina

  • Otimizado para a alegria do programador
  • Convenção sobre configuração
  • Omakase
  • Extremamente configurável
  • Monolítico
  • Entre outras...

Ruby on Rails

Um novo projeto

Deixe que o rails cuide de tudo para você

rails new app_name

Caso queira utilizar postgres em seu projeto

rails new app_name --database=postgresql

Por padrão, rails utiliza sqlite3. Para fazer deploy de seu projeto, porém, sqlite3 pode não funcionar!

Ruby on Rails

Um novo projeto

Inicie um servidor

rails s

Voilá

A estrutura de Rails é MVC!

A pasta assets guardará nossos CSS/JS e imagens

A pasta view, nossos HTML

Veremos as outras pastas depois

Adicionando uma nova página

Antes de mais nada, precisamos lembrar como funciona o MVC

  • Router
    • Controller
      • View
      • Model

Router ordena uma ação ao controller, que por sua vez chama a view relacionada e manipula o modelo se preciso

Adicionando uma nova página

1. Crie o controller o qual o router chamará

Isso deve ser feito na pasta controllers

# app/controllers/pages_controller.rb

# todo controller precisa herdar de ApplicationController
class PagesController < ApplicationController

  # Aqui dentro colocaremos nossas ações
  def homepage
  end

end

Adicionando uma nova página

2. Crie a view associada à ação do controller

  • Isso deve ser feito dentro da pasta com o nome do controller, dentro da pasta view
  • O nome do arquivo deve ser o mesmo da ação criada (no caso, homepage)
  • O arquivo contém apenas o que você colocaria dentro do body
  • A extensão do arquivo é ".html.erb"

Adicionando uma nova página

<!-- app/views/pages/homepage.html.erb -->

<h1>Hello world!</h1>

Adicionando uma nova página

3. Crie a rota que chamará a ação do controller

  • Isso deve ser feito no arquivo config/routes.rb, já criado pelo Rails
Rails.application.routes.draw do
  # For details on the DSL available...
end

Adicionando uma nova página

Montando uma rota

Basicamente, uma rota é construída da seguinte maneira

VERB '/path', to: 'controller#action'

Onde:

  • Verb é o verbo do HTTP request
    • Get, Post, Patch...
  • Path é o que virá após 'localhost:3000/' na url
  • 'controller' é o controller que queremos, 'action' a ação do controller que queremos

Adicionando uma nova página

Montando uma rota

Como queremos chamar o homepage do pages_controller, uma possível construção seria

get 'home', to: 'pages#homepage'

Adicionando uma nova página

Resultado

Adicionando uma nova página

Rota padrão

Se quisermos que http://localhost:3000 nos leve à página criada, podemos fazer

get '/', to: 'pages#homepage'

ou

root to: 'pages#homepage'

Onde está meu head? Meu body? Que magia negra é essa???

O esqueleto da view

Sendo comum a todas as páginas, o esqueleto da view, com head, body, etc., é mantido no arquivo layout/application.html.erb, gerado automaticamente pelo Rails

<!DOCTYPE html>
<html>
  <head>
    <title>Example</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <!-- ... -->
  </head>

  <body>
    <%= yield %>
  </body>
</html>

Quanta dor de cabeça para uma página só...

It's a kind of magic (parte 1)

Para realizar todos os passos acima, digite no terminal

rails g controller pages homepage
  • g = generate
  • pages = nome do controller
  • homepage = nome da action

Páginas dinâmicas

Sendo um ".html.erb", nossas páginas aceitam código Ruby!

<!-- Código ruby é executado com <% %> -->

<% 3.times do %>

  <!-- Código ruby é "impresso" com <%=  %> -->
  <h1>Agora é <%= Time.now %></h1>
  <% sleep(1) %>
<% end %>

Páginas dinâmicas

Também conseguimos enviar variáveis do controller para a view

# app/controllers/pages_controller.rb

# todo controller precisa herdar de ApplicationController
class PagesController < ApplicationController

  # Aqui dentro colocaremos nossas ações
  def homepage
    # A seguinte variável é acessível na view 'pages/homepage.html.erb'
    # pois a mesma começa com '@'

    @nome = "João"
  end

end

Páginas dinâmicas

<!-- Código ruby é executado com <% %> -->

<h1>Oi! Eu sou o <%= @nome %></h1>

E se quisermos mandar da view ao controller?

Formulários

Tags form possuem dois atributos básicos para seu funcionamento:

  • Action: a url para onde as informações serão enviadas (rota!!)
  • Method: o verbo da requisição ao enviar (GET, POST, PATCH...)
    • Por padrão, method="GET"

Formulários

Exemplo básico

<form action="/pages/new_user" method="POST">
  <!-- Essa linha é necessária para autenticar nosso formulário -->
  <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
  <input type="text" name="nome">
  <input type="email" name="email">
  <input type="password" name="password">
  <input type="submit">
</form>

Para funcionar, precisamos criar o método 'new_user' em pages_controller e configurar a rota ao mesmo!

Formulários

Exemplo básico

Vamos forçar um erro em new_user...

class PagesController < ApplicationController

  # ...

  def new_user
    raise
  end
end

A tela de erro é nossa grande amiga!

Repare o terminal logo abaixo...

Formulários

Exemplo básico

As informações preenchidas no formulário são armazenadas (e acessadas) no controller através da hash params

O atributo de um input é, mais especificamente, armazenado em params[:input_name]

 

Teste! Digite params[:password] no terminal da tela de erro!

Existem outros modos de enviar informações que não via form?

Links

Links nada mais são do que HTTP Requests get. Quase como formulários que só possuem o botão de enviar.

O atributo href indica aonde a requisição será enviada

<a href="/">Go home</a>

Links

Para enviar parâmetros via links, basta colocá-los após o '?' na url, com o formato name=value&name=value&...

<a href="/pages/homepage?nome=Jack">Go home</a>

Links

class PagesController < ApplicationController

  def homepage
    # nome será o que recebermos como parâmetro
    # se não recebermos nada, então será 'João'
    @nome = params[:nome] || 'João'
  end

  # ...
end

E se quisermos links que fazem POST requests?

Link Helpers

Modo do Rails dinamicamente criar os links

<%= link_to TEXTO, PATH(name: value, name: value...) %>

Link helpers

Path?

Paths são os links dinâmicamente criados pelo Rails de acordo com as rotas criadas (escrever as rotas podem causar problemas no ambiente de produção).

 

Para verificar suas rotas, digite `rails routes` no terminal

Link helpers

Path?

Os prefix, sufixados com '_path', é o que colocaremos no link para ir à página relacionada

<%= link_to 'Go home', pages_homepage_path(name: 'Jack') %>

Link helpers

Como fazer um POST request?

Utilizando link helpers, mudar alguns atributos fica mais fácil. Mudar o método do link, por exemplo, pode ser feito da seguinte maneira

<%= link_to 'Go home', pages_new_user_path(nome: 'Jack'), method: :post %>

E o modelo?

Modelos e ActiveRecord

Revisão

  • De forma geral, cada modelo é uma tabela no nosso BD (pode não ser...)
  • Usamos ActiveRecord para acelerar e facilitar (muito) a manipulação do BD com Ruby
  • Migrações fazem alterações na estrutura do BD (novas tabelas, novas colunas, modificação/remoção de tabelas/colunas, referências...)
  • Validações são feitas no arquivo do modelo

Modelos e ActiveRecord em Rails

It's a kind of magic (parte 2)

Criar um modelo em Rails é tão simples quanto criar um controller.

rails g model nome_do_modelo atributo:tipo atributo2:tipo2

Caso não especificado, "tipo" é definido como string

Modelos e ActiveRecord em Rails

It's a kind of magic (parte 2)

rails g model aluno nome idade:integer ano:integer curso

Modelos e ActiveRecord em Rails

It's a kind of magic (parte 2)

# db/migrate/##########_create_alunos.rb

class CreateAlunos < ActiveRecord::Migration[5.2]
  def change
    create_table :alunos do |t|
      t.string :nome
      t.integer :idade
      t.integer :ano
      t.string :curso

      t.timestamps
    end
  end
end

Não esqueçam de rodar rake db:migrate no terminal para executar a migração!

Modelos e ActiveRecord em Rails

Popualndo o BD

Para que nosso BD não comece vazio, precisamos populá-lo. O código para fazer isso é feito em db/seeds.rb

Vamos popular nossa tabela Aluno com 10 alunos diferentes!

Modelos e ActiveRecord em Rails

Popualndo o BD

# db/seeds.rb

# Deleta todos os registros existentes primeiro
Aluno.delete_all

10.times do |i|
  Aluno.create(
    nome: "Aluno #{i}",
    idade: 18 + i,
    ano: 2009 + i,
    curso: ['BCC', 'Biologia', 'Eng. Florestal', 'Matemática'].sample
  )
end

Execute esse arquivo com `rails db:seed`

MVC em Rails

Um controller de um modelo possui, geralmente, 7 ações essenciais (podem ter mais ou menos):

  • Index (mostrar todos os modelos)
  • Show (mostrar um modelo específico)
  • New (formulário para criação de um novo modelo)
  • Create (ação sem view para validar a criação do modelo e armazená-lo no BD)
    • Em caso de sucesso, redireciona para o show
    • Em caso de falha, redireciona para o new

MVC em Rails

Um controller de um modelo possui, geralmente, 7 ações essenciais (podem ter mais ou menos):

  • Edit (formulário para edição de um modelo existente)
  • Update (ação sem view para validar a edição do modelo e armazená-lo no BD)
    • Em caso de sucesso, redireciona para o show
    • Em caso de falha, redireciona para o edit
  • Delete (ação sem view para deletar um modelo existente no BD)
    • Em caso de sucesso, redireciona para o index
    • Em caso de falha, redireciona para o show

MVC em Rails

Cada uma das ações essenciais possui, idealmente, um verbo indicado para o mesmo:

  • Index (GET)
  • Show (GET)
  • New (GET)
  • Create (POST)
  • Edit (GET)
  • Update (PATCH)
  • Delete (DELETE)

MVC em Rails

Com nosso modelo criado, podemos gerar um controller para o mesmo!

rails g controller alunos

Delete as views geradas para o update, create e delete!

Vamos programar essas ações!

0. As rotas

Sendo rotas extremamente comuns,  Rails possui uma maneira de gerá-las automaticamente com apenas uma linha de código em config/routes.rb: resources

# config/routes.rb


Rails.application.routes.draw do
    # ...
    resources :alunos
    # ...
end

0. As rotas

Dica: use `-g` para verificar as rotas de um controller específico 

1. Index

O Controller precisa recuperar todos os modelos e enviar para a view, que por sua vez vai listar os mesmos (com um link para o show de cada uma)

1. Index

Controller

class AlunosController < ApplicationController
  def index
    @alunos = Aluno.all
  end

  # ...
end

1. Index

View (views/aluno/index.html.erb)

<h1>Lista de alunos</h1>
<% @alunos.each do |aluno| %>
  <p><%= aluno.nome %></p>
<% end %>

1. Index

View

2. Show

Cada nome será um link para a página coinfos específicas do aluno

O Controller precisa recuperar um modelo específico, sendo que o id do mesmo será passado como parâmetro (params[:id]).

A view irá mostrar seus detalhes.

2. Show

Link (no index)

<h1>Lista de alunos</h1>
<% @alunos.each do |aluno| %>
  <p><%= link_to aluno.nome, aluno_path(aluno.id) %></p>
<% end %>

2. Show

Controller

class AlunosController < ApplicationController
  
  # ...

  def show
    @aluno = Aluno.find(params[:id])
  end

  # ...

end

2. Show

View

<h1><%= @aluno.nome %></h1>
<h2>Cursando <%= @aluno.curso %></h2>

<p>Possui <%= @aluno.idade %> anos e entrou em <%= @aluno.ano %></p>

2. Show

As outras rotas

Feitas as duas rotas de visualização, precisamos decidir onde teremos os links que levam às demais (antes de criá-las)

  • Podemos criar a partir do index? De uma outra página (uma página de perfil, um homepage, etc)?
  • Podemos editar a partir do index? Do show? Ambos?
  • Podemos deletar a partir do index? Do show? Ambos?

3. New & Create

Em formulários para manipulação de novos modelos, iremos utilizar o simple form. Com ele, muitas das coisas que faríamos manualmente estarão prontas

# Gemfile
gem 'simple_form'
# Terminal
bundle install
rails g simple_form:install

3. New & Create

Acesso

Como exemplo, criaremos um novo botão  no index para criarmos um novo aluno

<h1>Lista de alunos</h1>
<%= link_to 'Novo aluno', new_aluno_path %>

<% @alunos.each do |aluno| %>
  <p><%= link_to aluno.nome, aluno_path(aluno.id) %></p>
<% end %>

3. New & Create

Acesso

3.1. New

Controller

Não precisamos de nada no controller, apenas instanciar a ação

class AlunosController < ApplicationController

  # ...
  
  def new
  end
end

3.1. New

View

Na view, implementamos o simple_form. Os detalhes de implementação podem ser estudados na documentação

<%= simple_form_for Aluno.new do |f| %>
  <%= f.input :nome %>
  <%= f.input :idade %>
  <%= f.input :curso %>
  <%= f.input :ano %>
  <%= f.submit 'Criar novo usuário' %>
<% end %>

3.1. New

3.2. Create

Ações de manipulação de Banco de Dados (inserção, atualização e remoção) têm uma estrutura especial. As ações create e update, em particular, devem:

  • Selecionar o modelo a ser modificado
    • em create, o modelo é Modelo.new
    • em update, o modelo é Modelo.find(params[:id])
  • Atualizar o modelo utilizando strong params
    • em create, Modelo.new(modelo_params)
    • em update, [...].update(modelo_params)

​​Em seguida, as ações devem redirecionar para alguma página ou renderizar a anterior caso algo dê errado.

3.2. Create

Controller

No exemplo, a implementação do create poderia ser da seguinte forma:

class AlunosController < ApplicationController
  # ...  
  def create
    @aluno = Aluno.new(aluno_params)
    
    if @aluno.save
      redirect_to aluno_path(@aluno.id)
    else
      render :new
    end
  end

  private

  def aluno_params
    params.require(:aluno).permit(:nome, :idade, :ano, :curso)
  end
end

3.2. Create

Repare que não há view associada!

Se der certo, vá para o show. Se não der, volte para o new

4. Edit & Update

A mesma lógica de new & create se aplicam à edit & update. A única diferença é que um se trata de um modelo novo (Modelo.new) e o outro de um modelo existente, o qual recuperamos do BD com seu id (Modelo.find(params[:id])).

4. Edit & Update

Acesso

Vamos deixar o botão de edição na página específica do modelo (show).

<h1><%= @aluno.nome %></h1>
<h2>Cursando <%= @aluno.curso %></h2>

<p>Possui <%= @aluno.idade %> anos e entrou em <%= @aluno.ano %></p>

<!-- Não se esqueça de passar o id do aluno ao controller! -->
<%= link_to 'Edite esse aluno', edit_aluno_path(@aluno.id) %>

4. Edit & Update

Acesso

4.1. Edit

Controller

class AlunosController < ApplicationController

  # ...
  
  def edit
    @aluno = Aluno.find(params[:id])
  end
end

Só precisamos recuperar o aluno, dado o id que nos foi passado

4.1. Edit

View

A view é idêntica à new, mas teremos @aluno no lugar de Aluno.new

<%= simple_form_for @aluno do |f| %>
  <%= f.input :nome %>
  <%= f.input :idade %>
  <%= f.input :curso %>
  <%= f.input :ano %>
  <%= f.submit 'Criar novo usuário' %>
<% end %>

4.1. Edit

Os inputs são automaticamente preenchidos com as informações atuais do modelo!

4.2. Update

Controller

O controller deverá recuperar novamente o modelo de acordo com o id passado e então atualizá-lo com os strong params

class AlunosController < ApplicationController
  # ...  
  def update
    @aluno = Aluno.find(params[:id])

    if @aluno.update(aluno_params)
      redirect_to aluno_path(@aluno.id)
    else
      render :edit
    end
  end

  # ...
end

4.2. Update

5. Destroy

Destroy é uma ação simples de ser implementada. Basta passarmos um id ao controller, encontrá-lo no BD, deletá-lo e redirecionar o usuário.

5. Destroy

Acesso

Vamos deixar o botão de remoção na página específica do modelo (show).

<h1><%= @aluno.nome %></h1>
<h2>Cursando <%= @aluno.curso %></h2>

<p>Possui <%= @aluno.idade %> anos e entrou em <%= @aluno.ano %></p>

<!-- Não se esqueça de passar o id do aluno ao controller! -->
<%= link_to 'Edite esse aluno', edit_aluno_path(@aluno.id) %>

<!-- Não se esqueça de passar o id do aluno ao controller! -->
<%= link_to 'Delete esse aluno', aluno_path(@aluno.id), method: :delete %>

5. Destroy

5. Destroy

Controller

Destroy é uma ação simples de ser implementada. Basta passarmos um id ao controller, encontrá-lo no BD, deletá-lo e redirecionar o usuário.

class AlunosController < ApplicationController
  # ...  
  def destroy
    @aluno = Aluno.find(params[:id])

    if @aluno.destroy
      redirect_to alunos_path # index
    else
      render :show
    end
  end

  # ...
end

5. Destroy

Made with Slides.com