I'm doing a Rails blog tutorial and don't fully understand the following link_to code
<%= link_to 'Destroy Comment', [comment.post, comment],
method: :delete,
data: { confirm: 'Are you sure?' } %>
Why do I have to use:
[comment.post, comment]
and why can't I just write:
#post.comment
My second, related, question is that since I created the "destroy" action in the controller as follows:
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
Why don't I have to mention "destroy" in the link_to code?
<%= link_to 'Destroy Comment', [comment.post, comment],
method: :delete,
data: { confirm: 'Are you sure?' } %>
The reason why you have to supply both the Post object and the Comment to the link_to helper is because Comment is a nested resource in Post, and both IDs must be known in order to construct the URL. It's actually equivalent to:
link_to 'Destroy Comment', post_comment_path(comment.post, comment), ...
What it's doing is it's resolving the path helper for you, using url_for. See http://guides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects .
You don't have to mention destroy in your link_to because destroy is the name of the action. Your routes file outlines which controllers and actions are associated with which routes.
I assume that you're using resourceful routing, which is shorthand way of defining routes for all of the CRUD actions. See http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions for the mapping between HTTP verb and controller action. You'll see that delete is mapped to destroy, and you're using method: :delete on your link_to.
So there are a lot of things going on here.
1) My guess is that the link_to in the first part is within a loop. Is that true? That would be something like #post.comments.each do |comment|. If that's the case, then likely what's happening is you have comments nested under posts. That documentation can be found here. The brackets are to identify the comment, which you need a post id for. You could probably also do [#post, comment], which would work just as well. You can't just write #post.comment because it's not enough information to identify the correct comment.
2) Rails takes HTTP verbs to identify which action to call from the controller. You're sending an HTTP DELETE request to /posts/:post_id/comments/:id, which the routes file then figures out belongs to the comments controller. That documentation can be found here and here.
Related
I'm learning ruby and rails too. I understood how the link_to and deleting items worked with a single resource.
<%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %>
And this works since it uses the article_path and uses rails magic where it takes takes article.id although article was passed in and there was a route article with DELETE and it needed the :id
Prefix Verb URI Pattern Controller#Action
article GET /articles/:id(.:format) articles#show
DELETE /articles/:id(.:format) articles#destroy
However after nesting a resource inside it say, comments
To delete a comment it becomes
<%= link_to 'Destroy Comment', [comment.article, comment],
method: :delete, data: { confirm: 'Are you sure?' } %>
Here are the (relevant) routes for the nested resource (note :format is ommitted)
Prefix Verb URI Pattern Controller#Action
article_comment GET /articles/:article_id/comments/:id comments#show
DELETE /articles/:article_id/comments/:id comments#destroy
Controller code
def destroy
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
#comment.destroy
redirect_to article_path(#article)
end
View code
<h3>Comments</h3>
<% #article.comments.each do |comment| %>
<p>
<strong> <%= comment.username %> </strong>: <%= comment.body %>
<!-- link_to goes here -->
</p>
<% end %>
Q1)
Firstly, is there another syntax for deleting a comment i.e another way of doing [comment.article, comment] in the structure of article_comment_path(comment) (like with non-nested resources in the first code block).
Q2)
What does [comment.article, comment] mean/do and how does it translate to the correct route with
DELETE /articles/:article_id/comments/:id comments#destroy
(Rails has a lot of syntactic sugar (I come from a Java background) so as I code I'm trying not to use syntactic sugar until I fully understand it.)
This code is all from section 5.13 (non nested resources) and section 8 (nested resources) of guides.rubyonrails.org.
For Q1) I found an answer which was
The wanted alternative syntax is
article_comment_path(#article.id, comment.id)
So overall
<%= link_to 'Destroy comment', article_comment_path(#article.id, comment.id), method: :delete, data: {confirm: 'Are you sure?'} %>
This answer was helpful
And the reason why you need the id for the article and the comment is that they are required due to the way the DELETE route is structured. #article.id is needed for articles/:article_id/ andcomment.id is needed for comments/:id
I would also like to add article_comment_path(#article.id, comment.id) in the link_to can be replaced with [#article, comment]. However if using this array input approach you cannot specify specifically the id, the whole object must be passed. So you cannot do [#article.id, comment.id] (Although I somewhat understand this array syntax with link_to im yet to get how q2 works).
I have been following a polymorphic association example at this website
https://www.richonrails.com/articles/polymorphic-associations-in-rails#comments
unfortunately, the author did not provide a example of how to delete a interaction under either people model or business model.
I have interactions_controller.rb
def destroy
#context = context
#interaction = #context.interactions.find(params[:id])
#interaction.destroy
end
in routes.rb
resources :business do
resources :interaction
end
in businesses/1, show.html.erb, it has a list all interactions.
<% link_to 'delete', business_interaction_path([#business, interaction]), method: :delete, data: {confirm: 'Are you sure?'} %>
I tried to use this to delete an individual interaction, the error message told me that it could find the business.id number, but cannot find interaction.id number.
This is both polymorphic association and nested resources so I got confused.
Can you tell me what I did wrong? Please you must understand this tutorial first before answering? Thanks!
<% link_to 'delete', business_interaction_path(#business, interaction), method: :delete, data: {confirm: 'Are you sure?'} %>
def destroy
#context = context
#interaction = #context.interactions.find(params[:id])
#interaction.destroy
redirect_to context_url(context)
end
I forgot to redirect_to correct page after deleting. This is why it keeps giving me a error message.
Here's the line from my routes config file:
DELETE /posts/:post_id/comments/:id(.:format) posts/comments#destroy
I want to delete a single comment but I can't get the syntax right. Here's what I tried:
<% if current_user == comment.user %>
<span class="edit-delete-line"><p><small><%= link_to "Delete", post_comments_path([#commentable, comment]), method: :delete, data: { confirm: "Are you sure?" } %> </span>
</small></p>
<% end %>
That gives me a routing error. I also tried:
<% if current_user == comment.user %>
<span class="edit-delete-line"><p><small><%= link_to "Delete", post_comments_path(params([:post_id], [:comment_id])), method: :delete, data: { confirm: "Are you sure?" } %> </span>
</small></p>
<% end %>
I got "wrong number of argument" error this time. I know this should be simple, right???
You're trying to delete a single comment, so you need to use post_comment_path(#commentable, comment), not plural post_comments_path, which points at the index. If you have your controller set up to also accept the unnested resource (just /comments/:id), you can just use comment_path directly.
Check out the Rails routing guide for more details.
<%= content_tag :span, link_to("Delete", [#commentable, comment], method: :delete, data: { confirm: "Are you sure?" }), class: "edit-delete-line" if current_user == comment.user %>
This should get it working for you.
To give you a simple synopsis, you have to realize that the Rails routes are basically helper methods which are generated when you define your respective routes.
The route helpers themselves don't do anything except give you a dynamic way to call specific routes. For example, instead of "/posts/<%= #post.id %>", you can call posts_path(#post).
--
The Rails routes work very simply -- they take arguments like any other helper method.
Thus, if you call a route which requires specific values to be passed (for example post_comments_path(post_id, comment_id), you have to pass the respective values to the helper.
Therefore, you can call the following:
post_comments_path(#commentable, comment), method: :delete
... or if you're using link_to, you should be able to pass the respective data objects that you require:
link_to "Destroy", [#commentable, comment], method: :delete
I am beginner to ROR and I am following this tutorial http://guides.rubyonrails.org/getting_started.html.
So according to this tutorial I want to delete one post. But its not working it showing this error The action 'destroy' could not be found for PostsController
My post controller delete method looks like
def destroy
#post = Post.find(params[:id])
logger.debug "***********************: #{#post.id}"
#post.destroy
redirect_to posts_path
end
In routes I mentioned resource resources :posts but still it is giving error for destroy action. Am I doing something wrong. Need Help.
Did you mention the method as delete in your views?
If you are using Rails 4, you should do:
<%=link_to 'Destroy', post_path(post), method: :delete, data: { confirm: 'Are you sure?' } %>
In Rails 3:
<%=link_to 'Destroy', post_path(post), method: :delete, confirm: 'Are you sure?' %>
I have a List object, with nested Tasks. I have created a page that displays individual tasks, and also a page that allows a user to edit individual tasks. I now want to add the ability to delete a task from a list on the tasks edit page. Using the following code
<%= link_to 'Delete this task',#task, confirm: 'Are you sure?', method: :delete %>
yields
undefined task_path method
This code is on the show.html.erb page, where I call #task to display all of the data stored within the task, so I believe that this issue may be a routing error of some kind, however I cannot seem to figure it out.
The related controller method is
def destroy
#task = Task.find(params[:id])
#task.destroy
respond_to do |format|
format.html { redirect_to list_tasks_path(#task) }
format.json { head :ok }
end
end
I thought that with the delete method the #task I supplied would just be sent to the destroy method via params, but this error seems to be showing that this isn't exactly how it works. So how can I properly destroy a nested resource in Rails?
edit:
Here is the route file with nested resources:
MyApp::Application.routes.draw do
resources :lists do
resources :tasks
end
get "home/index"
root :to => 'home#index'
end
Thank you for your help!
You should have #list setup, or use #task.list (assuming you have a belong to relationship), and you could do the following:
<%= link_to "Delete this task", list_task_path(#task.list, #task), confirm: "Are you sure?", method: :delete %>
Cheers!
Try this:
<%= link_to 'Delete this task', list_task_path(#list, #task), confirm: 'Are you sure?', method: :delete %>
Or if you want it more compact (like you've written it):
<%= link_to 'Delete this task', [#list, #task], confirm: 'Are you sure?', method: :delete %>
Either way, since it's a nested resource, you must pass in both the #list and #task objects.