3. Deleting Content and Adding Link

Now that we have put in the update functionality, let's now add in functionality for deleting ideas.

To do this, let's add a destroy method in ideas_controller.rb. Add the following method right after the update method.

def destroy
  @idea = Idea.find(params[:id])
  @idea.destroy
  redirect_to root_path
end

Let's walk through this. First, we are saying again to find the idea with the id of params[:id] and then to store that idea in @idea.

Then we are saying .destroy that @idea. Lastly, we are telling it to redirect to root_path.

We've added the destroy method, but how do we call this method from the application? We're going to do that by creating a link to destroy ideas. Go into index.html.erb and let's add a delete link.

How do I make a link in Rails though?

In rails, we can make a link with link_to. In your HTML file, we've seen that you can put in ruby code by putting the ruby code inside <%= %>. We can construct link_tos like this:

<%= link_to 'Any text here', link_path_here, any_other_option_here %>

To figure out the link path, you simply type in rails routes and find the corresponding prefix, such as edit_idea or idea, and then add _path after that. For example edit_idea_path and idea_path.

Let's take the index action for example. If we look at rails routes and look at the right most column, we see ideas#index. If we look all the way to the left on that row, we see the prefix of ideas. Therefore the link_to in this case would look something like this:

<%= link_to 'Link Title', ideas_path %>

If we want to add in any other options, like adding a CSS class or style to it, we can do that like this:

<%= link_to 'Link Title', ideas_path, class: 'my_class_here class_2', style: 'my_style_here style_2' %>

First, let's go into terminal and type in rails routes.

   Prefix Verb   URI Pattern               Controller#Action
     root GET    /                         ideas#index
    ideas GET    /ideas(.:format)          ideas#index
          POST   /ideas(.:format)          ideas#create
 new_idea GET    /ideas/new(.:format)      ideas#new
edit_idea GET    /ideas/:id/edit(.:format) ideas#edit
     idea GET    /ideas/:id(.:format)      ideas#show
          PATCH  /ideas/:id(.:format)      ideas#update
          PUT    /ideas/:id(.:format)      ideas#update
          DELETE /ideas/:id(.:format)      ideas#destroy

Let's look for the link to the destroy method. Let's look for the destroy method.

  DELETE /ideas/:id(.:format)      ideas#destroy
<%= link_to 'Delete', idea_path(idea) %>

Let's insert this into index.html.erb like this:

<% @ideas.each do |idea| %>
  <div class="rounded overflow-hidden shadow-lg">
    <div class="px-6 py-8 h-full">
      <div class="font-bold text-xl mb-2"><%= idea.description %></div>
      <p class="text-sm text-gray-700"><%= idea.author %></p>
      <div class="mt-4">
        <%= link_to 'Delete', idea_path(idea) %>
      </div>
    </div>
  </div>
<% end %>

The idea in between the ()s after idea_path refer to the idea declared by the each loop. It is just another parameter that we need to pass through to let rails know which idea we are destroying.

Unfortunately with this link, we can't tell rails to destroy the idea. If you take a look at rails routes, we see that idea_path is shared by other VERBs such as GET, PATCH, PUT.

  idea GET    /ideas/:id(.:format)      ideas#show
       PATCH  /ideas/:id(.:format)      ideas#update
       PUT    /ideas/:id(.:format)      ideas#update
       DELETE /ideas/:id(.:format)      ideas#destroy

By default, link_to will create links that make GET requests. To make a DELETE request, we need to specify that in our link_to. We can do this by adding method: :delete as an option like this:

<%= link_to 'Delete', idea_path(idea), method: :delete %>

But since rails 7, the link_to will not work for using method delete. We will need to create a form around a delete button. And, then we can tell the button to submit the form using the method delete. We want to alert the user that they are deleting an idea. We want to display some sort of pop up. We can do this by adding data: {turbo_confirm: "Are you sure?"} like this. It would look something like below.

<%= button_to 'Delete', idea_path(idea), method: :delete, form: { data: {turbo_confirm: "Are you sure?"}} %>

Save the file and refresh the page. We now have a working delete button. Now let's just add some design by giving it some tailwind styled buttons and then pulling it all the way to the right:

<%= button_to 'Delete', idea_path(idea), method: :delete, class: 'text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 focus:outline-none dark:focus:ring-red-800', form: { data: {turbo_confirm: "Are you sure?"}} %>

Awesome! Let's now add this button for each of our ideas. In index.html.erb, let's insert the link we just created, like this:

<% @ideas.each do |idea| %>
  <div class="rounded overflow-hidden shadow-lg">
    <div class="px-6 py-8 h-full">
      <div class="font-bold text-xl mb-2"><%= idea.description %></div>
      <p class="text-sm text-gray-700"><%= idea.author %></p>
      <div class="mt-4">
        <%= button_to 'Delete', idea_path(idea), method: :delete, class: 'text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 focus:outline-none dark:focus:ring-red-800', form: { data: {turbo_confirm: "Are you sure?"}} %>
      </div>
    </div>
  </div>
<% end %>

Save the file and refresh the page. If we click on the delete button, we see that a button saying "Are you sure?" pops up. Awesome.

While we're at it, let's also add a link to edit ideas. I'm going to call this button "Revise" instead of "Edit", just because I think it sounds cooler :)

If we go back to rails routes, we see that the prefix is edit_idea. That means our link_to is going to look something like this:

<%= link_to 'Revise', edit_idea_path(idea) %>

Let's paste that code under the delete button and refresh the page.

<% @ideas.each do |idea| %>
  <div class="rounded overflow-hidden shadow-lg">
    <div class="px-6 py-8 h-full">
      <div class="font-bold text-xl mb-2"><%= idea.description %></div>
      <p class="text-sm text-gray-700"><%= idea.author %></p>
      <div class="flex mt-4">
        <%= button_to 'Delete', idea_path(idea), method: :delete, class: 'text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 focus:outline-none dark:focus:ring-red-800', form: { data: {turbo_confirm: "Are you sure?"}} %>
        <%= link_to 'Revise', edit_idea_path(idea) %>
      </div>
    </div>
  </div>
<% end %>

We see that the link is there, but it would probably look better if this link also had a button to it. Let's give it the same class as the delete button and add classes to look like the following:

<% @ideas.each do |idea| %>
  <div class="rounded overflow-hidden shadow-lg">
    <div class="px-6 py-8 h-full">
      <div class="font-bold text-xl mb-2"><%= idea.description %></div>
      <p class="text-sm text-gray-700"><%= idea.author %></p>
      <div class="flex mt-4">
        <%= button_to 'Delete', idea_path(idea), method: :delete, class: 'text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 focus:outline-none dark:focus:ring-red-800', form: { data: {turbo_confirm: "Are you sure?"}} %>
        <%= link_to 'Revise', edit_idea_path(idea), class: 'text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800' %>
      </div>
    </div>
  </div>
<% end %>

If we refresh the page, we see that the buttons are now neatly aligned.

Deploying to Heroku (Optional)

After going through the standard git workflow, let's deploy all of the new changes that we have made to Heroku.

git push heroku master

Every time we push to Heroku, we should run migrations on the production server:

heroku run rails db:migrate

Then we should restart the server:

heroku restart

Awesome, let's move on to the next lesson.

Lesson list