-
Notifications
You must be signed in to change notification settings - Fork 0
14 Posts Delete
In this unit, we'll explore the following topics:
- Making
DELETE
requests - Ask users to confirm before following a link
Only one bit of CRUD left! Let's get ready to delete posts.
The controller bit looks a lot like what we've already been doing.
Implement PostsController#destroy
.
We can do something very similar to what we did for update
.
def destroy
post = Post.find params[:id]
if post.destroy
redirect_to posts_path, flash: { notice: 'Your post has been removed.' }
else
redirect_to posts_path, flash: { error: 'We were unable to remove that post.' }
end
end
Now, how to actually hit this method? There is no delete_post_path
helper. Let's look at our routes.
$ bin/rake routes
Prefix Verb URI Pattern Controller#Action
root GET / posts#index
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
Deletion uses the same URL as show
and update
. The difference is in in the HTTP verb, which must be DELETE
.
The link_to
helper provides an option for specifying the HTTP method (as HTTP verbs are formally known; method just happens to be an overloaded word in object-oriented programming).
link_to 'delete', post_path(@post), method: :delete
Let's add something like that to posts/index
.
app/views/posts/index.html.erb
<ul class="actions">
<li><%= link_to 'edit', edit_post_path(post) %></li>
<li><%= link_to 'delete', post_path(post), method: :delete %></li>
</ul>
From the documentation:
method
: symbol of HTTP verb - This modifier will dynamically create an HTML form and immediately submit the form for processing using the HTTP verb specified. Useful for having links perform aPOST
operation in dangerous actions like deleting a record (which search bots can follow while spidering your site). Supported verbs are:post
,:delete
,:patch
, and:put
. Note that if the user has JavaScript disabled, the request will fall back to usingGET
.
Try it out in your browser, and you should be able to delete posts. In fact, you can delete them alarmingly quickly. We can add a confirmation prompt by adding the data-confirm
attribute to the link. With the link_to
helper, data-
attributes can be set in a hash, like so:
link_to 'delete', post_path(@post), method: :delete, data: { confirm: 'Are you sure? This cannot be undone.' }
Let's add the confirmation to our view.
app/views/posts/index.html.erb
<ul class="actions">
<li><%= link_to 'edit', edit_post_path(post) %></li>
<li><%= link_to 'delete', post_path(post), method: :delete, data: { confirm: 'Are you sure? This cannot be undone.' } %></li>
</ul>
Try it again, and it should be bit less alarming.
We'll want the same link to appear on posts/show
. In fact, the overlap between these two views is beginning to get ridiculous.
Extract the common elements from posts/index
and posts/show
into one or more partials.
I created two partials: slug
, to hold the title and tagline; and actions
to hold the action links. Both partials require a Post
object to be passed as a local named post
.
_app/views/posts/slug.html.erb
<div class="title"><a href="<%= post_url(post) %>"><%= post.title %></a></div>
<div class="tagline" title="<%= post.created_at %>">submitted <%= time_ago_in_words post.created_at %> ago</div>
_app/views/posts/actions.html.erb
<ul class="actions">
<li><%= link_to 'edit', edit_post_path(post) %></li>
<li><%= link_to 'delete', post_path(post), method: :delete, data: { confirm: 'Are you sure? This cannot be undone.' } %></li>
</ul>
app/views/posts/index.html.erb
<ul class="posts">
<% @posts.each do |post| %>
<li>
<%= render 'slug', post: post %>
<%= render 'actions', post: post %>
</li>
<% end %>
</ul>
app/views/posts/show.html.erb
<article class="post">
<%= render 'slug', post: @post %>
<section class="body"><%= @post.body %></section>
<%= render 'actions', post: @post %>
</article>
If all is well, index
and show
should both look and behave exactly as they did before.