Find and Delete a Record

Extract Finding A Post

Now, post editing works, but if you were to look at the beginning of our show_post and edit_post actions, you'd notice that the logic to look up a post in the database is the same in each. So before we move on, let's take a moment to refactor this logic into its own method to make it more reusable.

### app/controllers/application_controller.rb ###

class ApplicationController < ActionController::Base

  # ...

  def show_post
    post = find_post_by_id(params['id'])

    render 'application/show_post', locals: { post: post }
  end

  # ...

  def edit_post
    post = find_post_by_id(params['id'])

    render 'application/edit_post', locals: { post: post }
  end

  # ...

  def find_post_by_id(id)
    connection.execute("SELECT * FROM posts WHERE posts.id = ? LIMIT 1", id).first
  end
end

Here we simply move the line we've been using to look up individual posts into its own method, named find_post_by_id. Then we use it in both show_post and edit_post like so:

post = find_post_by_id(params['id'])

Again, refactoring our logic into one place like this makes it:

  1. easy to change later, because now we'll only need to make a change in one place
  2. easy to use elsewhere if needed

Delete a Post

NOTE: Make sure not to delete the three original posts, or you may run into errors later in the book.

At this point we can view posts, create them, edit them, but we can't yet delete them, so that'll be our next step.

To do this, we'll just need something a user can click to send a request that deletes a post. But since deleting a post is destructive, we won't want to use a GET request for this. Instead, we'll use a POST request, and to perform this POST, we'll need to create a <form> to submit.

This <form> will be incredibly simple though, because it will have no <input>s, except for a submit button. All it needs to do is POST to the path for destroying the post.

Here's what it looks like:

<!-- app/views/application/list_posts.html.erb -->

<html>
  <body>

    <div class="posts">
      <% posts.each do |post| %>
        <div class="post">
          <h2 class="title"> <!-- ... --> </h2>

          <small class="meta">

            <!-- ... -->

          </small>
          <!-- ... -->
          <form method="post" action="/delete_post/<%= post['id'] %>" style='display: inline'>
            <input type="submit" value="Delete" />
          </form>
        </div>
        <hr />
      <% end %>
    </div>

    <!-- ... -->

  </body>
</html>

Then the route our new <form> points to:

### config/routes.rb ###

Rails.application.routes.draw do
  # ...
  post '/delete_post/:id' => 'application#delete_post'
end

And the action that routes to:

### app/controllers/application_controller.rb ###

class ApplicationController < ActionController::Base

  # ...

  def delete_post
    connection.execute("DELETE FROM posts WHERE posts.id = ?", params['id'])

    redirect_to '/list_posts'
  end
end

We start off in application/list_posts by giving each of our posts a <form>:

<form method="post" action="/delete_post/<%= post['id'] %>" style='display: inline'>
  <input type="submit" value="Delete" />
</form>

This will result in a Delete button for each post.

The <form> action has the format /delete_post/:id, so we route those requests to application#delete_post.

Inside application#delete_post, we see the familiar pattern we noticed in create_post and update_post (the other actions that receive POST requests):

  1. make a change to the database
  2. redirect

Now is a good time to go and try out some of the functionalities we've built into our app. We should now be able to create, edit, and delete posts.