Lesson 8

Destroy Actions and the RestfulizerJS Library

Our web application supports most of the standard CRUD functionality, but we haven't tackled deleting content from our database yet. We will do that in this lesson.

From our web application we'll want to trigger a DELETE HTTP request to the quote_path in our application. Rather than doing this through submitting a form, we should trigger the HTTP request by clicking on a link. Unfortunately, right now Phoenix doesn't support links to non-GET requests out of the box. We can pull in a JavaScript library to do this for us called the RestfulizerJs.

RestfulizerJs

Add the RestfulizerJs to your Phoenix web application. To start with copy the jquery.restfulizer.js file into priv/static/js folder.

We'll also want to include jQuery, so let's pull that into our application too. We should place this within the web/templates/layout/application.html.eex file, so the JavaScript is loaded on all pages of our web application.

Pro-tip! The application.html.eex is like application.html.erb in rails.

Add the following two lines to web/templates/layout/application.html.eex:

<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="/js/jquery.restfulizer.js"></script>

In order to activate the RestfulizerJs plugin, and also tie in our CSRF token we'll need to add a bit of JavaScript code. Including this script tag to the web/templates/layout/application.html.eex will do the trick:

<script>
$(function() {
  $(".rest").click(function(d) {
    $('form').submit(function(s) {
      var input = $("<input>")
      .attr("type", "hidden")
      .attr("name", "csrf_token").val("<%= csrf_token(@conn) %>");
      $(s.target).append($(input));
    });
  });
  $(".rest").restfulizer({});
});
</script>

Save the file.

We now can quickly perform POST, PUT and DELETE HTTP requests from links.

Adding a Delete Link

Edit web/templates/quote/index.eex to add a link to delete the quote:

<table>
  <thead>
    <tr>
      <th>Saying</th>
      <th>Author</th>
      <th>Actions</th>
  </thead>
  <%= for q <- @quotes do %>
  <tr>
    <td>
      <a href="<%=quote_path(@conn, :show, q.id) %>">
        <%= q.saying %>
      </a>
    </td>
    <td>
      <%= q.author %>
    </td>
    <td>
      <a href="<%=quote_path(@conn, :edit, q.id) %>">
        Edit
      </a>
| <a href="<%= quote_path(@conn, :destroy, q.id) %>" data-method="DELETE" class="rest"> Destroy </a>
</td> </tr> <% end %> </table>

Save the file and refresh the index page. You should notice a destroy link got added. Sweet!

In the code above, by giving the link the class of rest we connect it to the script tag we used above to configure the RestfulizerJs library. The data-method attribute tells RestfulizerJs to perform that type of an HTTP request when the link is clicked, in this case a DELETE request.

When you press the destroy button you will be presented an error message, stating that we haven't implemented the action in the controller yet. Let's add the action in our controller!

Add the method to web/controllers/quote_controller.ex so the file looks like this:

defmodule Splurty.QuoteController do
  use Phoenix.Controller

  alias Splurty.Router
  import Splurty.Router.Helpers

  plug :action

  def homepage(conn, _params) do
    render conn, "homepage.html"
  end

  def index(conn, _params) do
    conn
    |> assign(:quotes, Repo.all(Splurty.Quote))
    |> render("index.html")
  end

  def new(conn, _params) do
    render conn, "new.html"
  end

  def create(conn, %{"quote" => %{"saying" => saying, "author" => author}}) do
    q = %Splurty.Quote{saying: saying,  author: author}
    Repo.insert(q)

    redirect conn, to: quote_path(conn, :index)
  end

  def show(conn, %{"id" => id}) do
    {id, _} = Integer.parse(id)
    conn
    |> assign(:quote, Repo.get(Splurty.Quote, id))
    |> render("show.html")
  end

  def edit(conn, %{"id" => id}) do
    {id, _} = Integer.parse(id)
    conn
    |> assign(:quote, Repo.get(Splurty.Quote, id))
    |> render("edit.html")
  end


  def update(conn, %{"id" => id, "quote" => %{"saying" => saying, "author" => author}}) do
    {id, _} = Integer.parse(id)
    q = Repo.get(Splurty.Quote, id)
    q = %{q | saying: saying, author: author }
    Repo.update(q)
    redirect conn, to: quote_path(conn, :show, q.id)
  end

def destroy(conn, %{"id" => id}) do {id, _} = Integer.parse(id) q = Repo.get(Splurty.Quote, id) Repo.delete(q) redirect conn, to: quote_path(conn, :index) end
end

Save the file.

This code uses the standard code we've been using to load up the Splurty.Quote model in the controller. We then delete the item from the repo in the same manner we used in Lesson 3. The user is redirected to the index of the QuoteController.

Press the destroy button. Sweet! You will be redirected to the index page and the item you deleted will no longer be presented to you in the table.

Your application should look just like this at this step.

Next Lesson