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 constructlink_to
s 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 correspondingprefix
, such asedit_idea
oridea
, and then add_path
after that. For exampleedit_idea_path
andidea_path
.Let's take the
index
action for example. If we look atrails routes
and look at the right most column, we seeideas#index
. If we look all the way to the left on that row, we see theprefix
ofideas
. Therefore thelink_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
orstyle
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.
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.