Chapter 10

The Contacts Module: Adding a Controller

10.1. Generating a Controller

Let’s generate a controller for our new model. But first… you guessed it! Let’s make a branch for our chapter:

git checkout -b Chapter-10

Right… back to our Controller:

Step 1: Generate it

Run the following command from the Contacts engine (i.e. engines/contacts)

rails g scaffold_controller Contact --no-helper

Step 2: Update the controller

First, we need to change the parent of ApplicationController to the ApplicationController present in the Core, as shown in Listing 1:

Listing 0.1: Update Contact module’s ApplicationController contacts/app/controllers/blast/contacts/application_controller.rb
module Blast
  module Contacts
    class ApplicationController < Blast::ApplicationController
    end
  end
end

We have a few things to change in the controller generated by Rails. First, we need to prefix all the path helpers with blast. Then, we need to update the contact_params method to include the parameters we want to keep.

Listing 2 shows the entire controller, including comments about what we changed, so you can just copy/paste it and read it.

Listing 0.2: Updated ContactsController contacts/app/controllers/blast/contacts/contacts_controller.rb
require_dependency "blast/contacts/application_controller"

module Blast
  module Contacts
    class ContactsController < ApplicationController
      before_action :set_contact, only: [:show, :edit, :update, :destroy]

      def index
        @contacts = Contact.all
      end

      def show
      end

      def new
        @contact = Contact.new
      end

      def edit
      end

      def create
        @contact = Contact.new(contact_params)
        @contact.user = current_user

        if @contact.save
          # Add blast to access the correct path
          redirect_to [blast, @contact],
                      notice: 'Contact was successfully created.'
        else
          render :new
        end
      end

      def update
        if @contact.update(contact_params)
          # Add blast to access the correct path
          redirect_to [blast, @contact],
                      notice: 'Contact was successfully updated.'
        else
          render :edit
        end
      end

      def destroy
        @contact.destroy
        # Add blast to access the correct path
        redirect_to blast.contacts_url,
                    notice: 'Contact was successfully destroyed.'
      end

      private

        def set_contact
          @contact = Contact.find(params[:id])
        end

        def contact_params
          # Add the parameters we allow
          params.require(:contact).permit(:first_name, :last_name, :company,
                                          :email, :phone, :user_id)
        end
    end
  end
end

Step 3: Update the views

We prepared some views so you don’t have to think about it. They are basic views with Bootstrap forms and elements. The only thing that you should remember in those views, is the use of blast.my_path instead of just my_path. Copy/paste them appropriately:

Listing 0.3: index.html.erb contacts/app/views/blast/contacts/contacts/index.html.erb
<%= link_to 'New Contact', blast.new_contact_path,
            class: 'float-right btn btn-primary' %>

<h2>Listing Contacts</h2>
<hr>
<div class="panel panel-primary">
  <div class="panel-heading">
    My Contacts
  </div>

  <table class="table">
    <thead>
      <th>ID</th>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Company</th>
      <th>Email</th>
      <th>Phone</th>
      <th></th>
    </thead>
    <tbody>
      <% @contacts.each do |contact| %>
        <tr>
          <td><%= contact.id %></td>
          <td><%= contact.first_name %></td>
          <td><%= contact.last_name %></td>
          <td><%= contact.company %></td>
          <td><%= contact.email %></td>
          <td><%= contact.phone %></td>
          <td>
            <%= link_to 'Show', [blast, contact],
                        class: 'btn btn-primary' %>
            <%= link_to 'Edit', blast.edit_contact_path(contact),
                        class: 'btn btn-primary' %>
            <%= link_to 'Destroy', [blast, contact],
                        class: 'btn btn-primary' , method: :delete,
                        data: { confirm: 'Are you sure?' } %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
<br>
Listing 0.4: _form.html.erb contacts/app/views/blast/contacts/contacts/_form.html.erb
<div class="row">
  <div class="col-md-8">
    <% if @contact.errors.any? %>
      <div id="error_explanation">
        <h2>
         <%= pluralize(@contact.errors.count, "error") %>
         prohibited this contact from being saved:</h2>
        <ul>
        <% @contact.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
        </ul>
      </div>
    <% end %>
    <div class="form-group">
      <%= f.label :first_name, class: "control-label" %>
      <%= f.text_field :first_name, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :last_name, class: "control-label" %>
      <%= f.text_field :last_name, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :company, class: "control-label" %>
      <%= f.text_field :company, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :email, class: "control-label" %>
      <%= f.email_field :email, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :phone, class: "control-label" %>
      <%= f.text_field :phone, class: "form-control" %>
    </div>
  </div>
</div>
Listing 0.5: new.html.erb contacts/app/views/blast/contacts/contacts/new.html.erb
<h2>New Contact</h2>
<hr>

<%= form_for([blast, @contact]) do |f| %>
  <%= render 'form', f: f %>

  <div class="form-group">
    <div>
        <%= f.submit "Create Contact", class: "btn btn-primary" %>
        <%= link_to 'Back', blast.contacts_path, class: 'btn btn-default' %>
    </div>
  </div>
<% end %>
Listing 0.6: show.html.erb contacts/app/views/blast/contacts/contacts/show.html.erb
<h2><%= @contact.first_name %></h2>
<hr>

<div class="row">
  <div class="col-md-8">
    <strong>First Name:</strong>
    <%= @contact.first_name %>
    <br/>
    <strong>Last Name:</strong>
    <%= @contact.last_name %>
    <br/>
    <strong>Company:</strong>
    <%= @contact.company %>
    <br/>
    <strong>Email:</strong>
    <%= @contact.email %>
    <br/>
    <strong>Phone:</strong>
    <%= @contact.phone %>
  </div>
</div>
<hr>
<%= link_to 'Edit', blast.edit_contact_path(@contact), class: "btn btn-primary" %>
<%= link_to 'Back', blast.contacts_path, class: 'btn btn-default' %>
Listing 0.7: edit.html.erb contacts/app/views/blast/contacts/contacts/edit.html.erb
<h2>Editing Contact</h2>
<hr>

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

That’s it for the views!

Step 4: Add the routes

If we want to access the contacts somehow, we need to define some routes for it. Let’s add them as you can see in Listing 8:

Listing 0.8: Adding Contacts routes contacts/config/routes.rb
Blast::Core::Engine.routes.draw do
  scope module: 'contacts' do
    resources :contacts
  end
end

Note that we are just extending the Core routes. This means that in any of our Blast engines, all the routes are easily accessible by using blast.my_path.

Step 5: Try it!

Let’s see what it looks like in the browser. Access http://localhost:3000/contacts and you should see Figure 1:

https://s3.amazonaws.com/devblast-modr-book/images/figures/03_10/listing_contacts_default
Figure 1

Ow, not that great, huh? Why don’t we see the beautiful layout that we created in the Core? Because we have a layout in Contacts that overrides the Core version.

Step 6: Remove the layouts folder.

Simply delete the layouts folder in the Contacts engine or run the following command from the Contacts folder.

rm -r app/views/layouts

Step 7: Try it again!

Restart your server and refresh your page, and you should see Figure 2:

https://s3.amazonaws.com/devblast-modr-book/images/figures/03_10/listing_contacts_core_layout
Figure 2

Nice! But hey, having to type the url is annoying… we want a link in our menu!

We’ll fix that in the next chapter.

10.2. Pushing Our Changes

Once again,

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

10.3. Wrap Up

In this chapter we added our Contacts Controller and its related views.

10.3.1. What did we learn?

  • Accessing our routes using blast.my_path by extending the Core routes.

10.3.2. Next Step

In the next chapter we will learn how to extend the Core views and add a “Contacts” link in the Navigation bar.