Skip to content

1 Tutorial CRUD

Pedro Germano Cervi edited this page Jul 6, 2019 · 4 revisions

Setup

Siga as instruções do README do projeto para executar a aplicação. Para esse tutorial vamos precisar executar os testes da pasta tutorials/crud_tutorial somente com: rspec spec/tutorials/crud_tutorial/*.

Criação da tabela Releases no Banco de dados

executar: rails generate migration create_releases alterar arquivo gerado:

class CreateReleases < ActiveRecord::Migration[5.2]
  def change
    create_table :releases do |t|
      t.string :title, null: false
      t.string :release_type
      t.integer :year
      t.integer :discog_id

      t.timestamps

      t.belongs_to :artist, index: true, null: false
    end
  end
end

executar: rails db:migrate

Associação dos models Artists e Releases

Criar model Release

Na pasta app/models criar um arquivo com o nome release.rb Nesse arquivo incluir o seguinte código:

class Release < ApplicationRecord
  belongs_to :artist
end

Na mesma pasta modificar o arquivo artist.rb incluindo a seguinte linha dentro da classe:

  has_many :releases
Criar factory para o model Release

Na pasta spec/factories criar um arquivo com o nome releases.rb Nesse arquivo incluir o seguinte código:

FactoryBot.define do
  factory :release do
    title { Faker::Movies::HitchhikersGuideToTheGalaxy.character }

    artist
  end
end

executar rspec spec/tutorials/crud_tutorial/models/* todos os testes devem passar.

acessar o console com rails console executar a factory com Factory.bot.create(:release)

Criar rotas para o CRUD de Releases

no arquivo config/routes.rb modificar a linha: resources :artists para seguinte forma:

  resources :artists do
    resources :releases
  end

Criar ação index para Releases

na pasta app/controllers criar um arquivo com o nome releases_controller.rb nesse arquivo incluir o seguinte código:

class ReleasesController < ApplicationController
  def index; end
end

na pasta app/views criar uma pasta chamada releases e dentro dela um arquivo com o nome index.html.erb. Nesse arquivo incluir o seguinte código:

<p id="notice"><%= notice %></p>

<div class="card mb-3">
  <div class="card-header">
    <i class="fas fa-compact-disc"></i>
    Releases
  </div>
  <div class="card-body">
    <div class="table-responsive">
      <table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
        <thead>
          <tr>
            <th>Title</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          <% @releases.each do |release| %>
            <tr>
              <td><%= release.title %></td>
              <td class="text-center">
                <!-- TODO links -->
              </td>
            </tr>
          <% end %>
        </tbody>
      </table>
    </div>
  </div>
</div>

no arquivo app/controllers/releases_controller.rb modificar a ação index para o seguinte formato:

  def index
    @artist = Artist.find(params[:artist_id])

    @releases = @artist.releases
  end

executar rspec spec/tutorials/crud_tutorial/controllers/releases_controller_spec.rb. um dos testes deve passar.

executar rails server no browser acessar /artists/<id>/releases deve listar as releases já criadas para o artist com a id selecionada.

Criar ação show para Releases

inserir no arquivo app/controllers/releases_controller.rb a seguinte função:

  def show
    @artist = Artist.find(params[:artist_id])
    @release = Release.find(params[:id])
  end

na pasta app/views/releases criar um arquivo com o nome show.html.erb nesse arquivo inserir o seguinte código:

<p id="notice"><%= notice %></p>

<div class="card mb-3">
  <div class="card-header">
    <i class="fas fa-compact-disc"></i>
    <%= @release.title %>
  </div>
  <div class="card-body">
    <p>Year: <%= @release.year %></p>
    <p>Artist: <%= @artist.name %></p>
  </div>
</div>

executar rspec spec/tutorials/crud_tutorial/controllers/releases_controller_spec.rb. dois dos testes devem passar.

executar rails server no browser acessar /artists/<artist_id>/releases/<id> deve mostrar a release selecionada.

Criar ações new/create para Releases

no arquivo app/controllers/releases_controller.rb inserir as seguintes funções:

  def new
    @artist = Artist.find(params[:artist_id])
    @release = Release.new(artist: @artist)
  end

  def create
    @release = Release.new(release_params)
    @artist = Artist.find(params[:artist_id])
    @release.artist = @artist

    if @release.save
      redirect_to artist_release_url(artist_id: @artist.id, id: @release.id), notice: 'Release was successfully created.'
    else
      render :new
    end
  end

  private

  def release_params
    params.require(:release).permit(
      :title
    )
  end

na pasta app/views/releases criar um arquivo com o nome new.html.erb nesse arquivo inserir o seguinte código:

<div class="card mb-3">
  <%= form_with(model: [ @artist, @artist.releases.build ], local: true) do |form| %>
    <div class="card-body">
      <div class="row">
        <div class="col-12">
          <% if @release.errors.any? %>
            <div id="error_explanation">
              <h2>
                <%= pluralize(@release.errors.count, "error") %> prohibited
                this release from being saved:
              </h2>
              <ul>
                <% @release.errors.full_messages.each do |msg| %>
                  <li><%= msg %></li>
                <% end %>
              </ul>
            </div>
          <% end %>
          <div class="form-group">
            <label for="title" class="control-label custom-control-label">Title</label>
            <div class="input-group">
              <span class="input-group-addon"><i class="fas fa-compact-disc" aria-hidden="true"></i></span>
              <input type="text" class="form-control" id="release-title" name="release[title]" value="<%= @release.title %>">
            </div>
          </div>
        </div>
      </div>

      <div class="row">
        <button type="submit" class="btn btn-primary btn-lg btn-block login-button">Save</button>
      </div>
    </div>
  <% end %>
</div>

Criar ações edit/update

no arquivo app/controllers/releases_controller.rb adicionar as seguintes funções:

  def edit
    @artist = Artist.find(params[:artist_id])
    @release = Release.find(params[:id])
    render :edit
  end

  def update
    @artist = Artist.find(params[:artist_id])
    @release = Release.find(params[:id])

    if @release.update(release_params)
      redirect_to artist_release_url(artist_id: @artist.id, id: @release.id), notice: 'Release was successfully updated.'
    else
      render :edit
    end
  end

na pasta app/views/releases ciar um arquivo com o nome edit.html.erb. Nesse arquivo adicionar o seguinte código:

<div class="card mb-3">
  <%= form_with(model: [ @artist, @release ], local: true) do |form| %>
    <div class="card-body">
      <div class="row">
        <div class="col-12">
          <% if @release.errors.any? %>
            <div id="error_explanation">
              <h2>
                <%= pluralize(@release.errors.count, "error") %> prohibited
                this release from being saved:
              </h2>
              <ul>
                <% @release.errors.full_messages.each do |msg| %>
                  <li><%= msg %></li>
                <% end %>
              </ul>
            </div>
          <% end %>
          <div class="form-group">
            <label for="title" class="control-label custom-control-label">Title</label>
            <div class="input-group">
              <span class="input-group-addon"><i class="fas fa-compact-disc" aria-hidden="true"></i></span>
              <input type="text" class="form-control" id="release-title" name="release[title]" value="<%= @release.title %>">
            </div>
          </div>
        </div>
      </div>

      <div class="row">
        <button type="submit" class="btn btn-primary btn-lg btn-block login-button">Save</button>
      </div>
    </div>
  <% end %>
</div>

Criar ação destroy para Releases

no arquivo app/controllers/releases_controller.rb incluir a seguinte função:

  def destroy
    @artist = Artist.find(params[:artist_id])
    @release = Release.find(params[:id])

    @release.destroy

    redirect_to artist_releases_url, notice: 'Release was successfully destroyed.'
  end

Linkando as funcionalidades na interface

no arquivo app/views/artists/show.html.erb adicionar o seguinte link após profile

  <p><%= link_to 'Releases', artist_releases_path(@artist) %></p>

no arquivo app/views/releases/index.html.erb modificar a linha Releases para o seguinte formato:

  Releases by <%= link_to "#{@artist.name}", artist_path(@artist) %>

no mesmo arquivo, substituir o comentário <!-- TODO links --> por:

  <%= link_to edit_artist_release_path(artist_id: @artist.id, id: release.id) do %>
    <i class="fas fa-pencil-alt"></i>
  <% end %>
  <%= link_to artist_release_path(artist_id: @artist.id, id: release.id), method: :delete, data: { confirm: 'Are you sure?' } do %>
    <i class="fas fa-times"></i>
  <% end %>

ainda no mesmo arquivo, onde temos <td><%= release.title %></td> colocar:

  <td><%= link_to release.title, artist_release_path(artist_id: @artist.id, id: release.id) %></td>

no arquivo app/views/releases/show.html.erb onde temos <p>Artist: <%= @artist.name %></p> colocar:

  <p>Artist: <%= link_to @artist.name, artist_path(@artist) %></p>

por fim, no arquivo app/views/releases/index.html.erb inclua um botão para criar releases:

  <br>

  <%= link_to(t('.new'), new_artist_release_path(@artist.id), class: "btn btn-primary btn-lg btn-block login-button") %>