Chapter 15

The Tasks Module: Controllers & Views

In this chapter we’re going to add a controller and the basic views for our tasks. But first, let’s create our chapter branch:

git checkout -b Chapter-15

15.1. Adding our Tasks Controllers & Views

15.1.1. Generate the Tasks controllers in the Tasks engine

Navigate to the Tasks engine and run the following command to create the tasks controller:

rails g scaffold_controller Task --no-helper

15.1.2. Update the ApplicationController

Update the ApplicationController to inherit from the Blast::ApplicationController:

Listing 0.1: Updating the Tasks ApplicationController app/controllers/blast/tasks/application_controller.rb
module Blast
  module Tasks
    class ApplicationController < Blast::ApplicationController
    end
  end
end

15.1.3. Update the TasksController

Update the TasksController to reflect the contents of Listing code::

Listing 0.2: Updated TasksController app/controllers/blast/tasks/tasks_controller.rb
require_dependency "blast/tasks/application_controller"

module Blast::Tasks
  class TasksController < ApplicationController
    before_action :set_task, only: [:show, :edit, :update, :destroy]

    # GET /tasks
    def index
      @tasks = Task.all
    end

    # GET /tasks/1
    def show
    end

    # GET /tasks/new
    def new
      @task = Task.new
    end

    # GET /tasks/1/edit
    def edit
    end

    # POST /tasks
    def create
      @task = Task.new(task_params)

      if @task.save
        redirect_to [blast, @task], notice: 'Task was successfully created.'
      else
        render :new
      end
    end

    # PATCH/PUT /tasks/1
    def update
      if @task.update(task_params)
        redirect_to [blast, @task], notice: 'Task was successfully updated.'
      else
        render :edit
      end
    end

    # DELETE /tasks/1
    def destroy
      @task.destroy
      redirect_to blast.tasks_url, notice: 'Task was successfully destroyed.'
    end

    private
      # Use callbacks to share common setup or constraints between actions.
      def set_task
        @task = Task.find(params[:id])
      end

      # Only allow a trusted parameter "white list" through.
      def task_params
        params.require(:task).permit(:title, :content, :user_id, :contact_id)
      end
  end
end

15.1.4. Update the Views

Copy/Paste the Listings below in the appropriate files:

Listing 0.3: Updated index view app/views/blast/tasks/tasks/index.html.erb
<%= link_to 'New Task', blast.new_task_path,
    class: 'pull-right btn btn-primary' %>

<h2>Listing Tasks</h2>
<hr>
<div class="panel panel-primary">
  <div class="panel-heading">
    My Tasks
  </div>
  <table class="table">
    <thead>
      <th>ID</th>
      <th>Title</th>
      <th>Content</th>
      <th>Created At</th>
      <th></th>
    </thead>
    <tbody>
      <% @tasks.each do |task| %>
        <tr>
          <td><%= task.id %></td>
          <td><%= task.title %></td>
          <td><%= task.content %></td>
          <td><%= task.created_at.strftime("%d %b. %Y") %></td>
          <td>
            <%= link_to 'Show', [blast, task], class: 'btn btn-primary' %>
            <%= link_to 'Edit', blast.edit_task_path(task),
                        class: 'btn btn-primary' %>
            <%= link_to 'Destroy', [blast, task],
                        class: 'btn btn-primary' , method: :delete,
                        data: { confirm: 'Are you sure?' } %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
<br>
Listing 0.4: Updated form view app/views/blast/tasks/tasks/_form.html.erb
<div class="row">
  <div class="col-md-8">
    <% if @task.errors.any? %>
      <div id="error_explanation">
        <h2>
         <%= pluralize(@task.errors.count, "error") %>
         prohibited this task from being saved:</h2>
        <ul>
        <% @task.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
        </ul>
      </div>
    <% end %>

    <div class="form-group">
      <%= f.label :title, class: "control-label" %>
      <%= f.text_field :title, class: "form-control" %>
    </div>

    <div class="form-group">
      <%= f.label :content, class: "control-label" %>
      <%= f.text_area :content, class: "form-control" %>
    </div>

    <div class="form-group">
      <%= f.label :user_id, class: "control-label" %>
      <%= f.select :user_id, Blast::User.all.collect { |p| [ p.email, p.id ] },
                   { selected: current_user.id }, class: "form-control" %>
    </div>
  </div>
</div>
Listing 0.5: Updated new view app/views/blast/tasks/tasks/new.html.erb
<h2>New Task</h2>
<hr>
<%= form_for([blast, @task]) do |f| %>
  <%= render 'form', f: f %>

  <div class="form-group">
    <div>
        <%= f.submit "Create Task", class: "btn btn-primary" %>
        <%= link_to 'Back', blast.tasks_path, class: 'btn btn-default' %>
    </div>
  </div>
<% end %>
Listing 0.6: Updated show view app/views/blast/tasks/tasks/show.html.erb
<h2><%= @task.title %></h2>
<hr>
<div class="row">
  <div class="col-md-8">
    <strong>Title:</strong>
    <%= @task.title %>
    <br/>
    <strong>Content:</strong>
    <%= @task.content %>
    <br/>
    <strong>User:</strong>
    <%= @task.user.email %>
    <br/>
  </div>
</div>
<hr>
<%= link_to 'Edit', blast.edit_task_path(@task), class: "btn btn-primary" %>
<%= link_to 'Back', blast.tasks_path, class: 'btn btn-default' %>
Listing 0.7: Updated edit view app/views/blast/tasks/tasks/edit.html.erb
<h2>Editing Task</h2>
<hr>

<%= form_for([blast, @task]) do |f| %>
  <%= render 'form', f: f %>
  <div class="form-group">
    <div>
      <%= f.submit "Update Task", class: "btn btn-primary" %>
      <%= link_to 'Back', blast.tasks_path, class: 'btn btn-default' %>
    </div>
  </div>
<% end %>

15.1.5. Remove the layouts/ folder

Remove the layouts/ folder so that our views use the Core layouts’ views (remember that it is within the Tasks engine folder):

rm -r app/views/layouts

15.1.6. Add the routes

Let’s add the routes so that we can see our beautiful views:

Listing 0.8: Updated task engine routes tasks/config/routes.rb
Blast::Core::Engine.routes.draw do
  scope module: 'tasks' do
    resources :tasks
  end
end

15.1.7. Add “Tasks” link to the navigation menu

We’re almost done with the boring part. Before we start extending the Contacts module, let’s add a link in the navigation menu to access the list of tasks.

Step 1: Create an override

Create the override file, and add to it the contents of Listing 9:

touch app/overrides/add_tasks_link_to_nav.rb

Step 2: Create a view for the override

Create the override view file, and add to it the contents of Listing 10:

touch app/views/blast/tasks/overrides/_tasks_link.html.erb

15.1.8. Fruits of our labour

Finally, let’s take a look at what we’ve done so far. Restart your server and you should see the “Tasks” link. Click on it and you should see Figure 1:

https://s3.amazonaws.com/devblast-modr-book/images/figures/04_15/initial_tasks_view
Figure 1: It looks Legen... wait for it... dary!! Ahem.

15.2. Pushing Our Changes

Let’s not forget to push our changes:

  1. Check the changes:
    git status
    
  2. Stage them:
    git add .
    
  3. Commit them:
    git commit -m "Added Tasks Controllers, Views and Task link"
    
  4. Push to your GitHub repo if you’ve configured it:
    git push origin Chapter-15
    

15.3. Wrap Up

We have added the Tasks controller and some views so that we can add, edit and delete tasks.

15.3.1. Next Step

In the next chapter we will display all the tasks that belong to a Contact in a list, under that Contact.