I am not able to find the right way to destroy a record. I feel like such a complete newb.
Here are the routes pertaining to the controller (output from rake routes):
contents GET /admin/contents(.:format) {:controller=>"contents", :action=>"index"}
contents POST /admin/contents(.:format) {:controller=>"contents", :action=>"create"}
new_content GET /admin/contents/new(.:format) {:controller=>"contents", :action=>"new"}
edit_content GET /admin/contents/:id/edit(.:format) {:controller=>"contents", :action=>"edit"}
content GET /admin/contents/:id(.:format) {:controller=>"contents", :action=>"show"}
content PUT /admin/contents/:id(.:format) {:controller=>"contents", :action=>"update"}
content DELETE /admin/contents/:id(.:format) {:controller=>"contents", :action=>"destroy"}
What is getting me is the bottom line does not look any different than the get and put.
Here is the link:
<%= link_to 'Destroy', content, :confirm => 'Are you sure?', :method => :delete %>
also tried:
<%= link_to 'Destroy', content, :confirm => 'Are you sure?', :method => :destroy %>
and the output is:
Destroy
Can someone spot what I am doing wrong here? :-/
edit
I did not intially have rails.js loading. I do now.
Here is the contents of my destroy action:
def destroy
#content = Content.find(params[:id])
#content.destroy
respond_to do |format|
format.html { redirect_to(contents_url) }
format.xml { head :ok }
end
end
I am deleting from the content index, like so:
<% #contents.each do |content| %>
<tr>
<td><%= content.name %></td>
<td><%= link_to 'Show', content %></td>
<td><%= link_to 'Edit', edit_content_path(content) %></td>
<td><%= link_to 'Destroy', content, :confirm => 'Are you sure?', :method => :destroy %></td>
</tr>
<% end %>
</table>
The URL looks the same because it is the same. The difference lie within the request method. Your Rails app knows to separate GET, PUT and DELETE requests--even if they are made to the same URL--and route the request to the right action.
However, not all browsers/web servers support all of these methods, so Rails rely upon unobtrusive JavaScript (ujs) to "fake" some of the requests--more specifically, PUT and DELETE. Because of this, you'll need to include one of the bundles for Rails apps (the Prototype comes by default; you can get the jQuery version through this gem). You can find out more through the README (and of course the source) of the jQuery ujs.
If you're experiencing issues, it's probably because you don't have the necessary ujs. It could also be that you haven't included the csrf_meta_tag in your html header.
A few things could be going wrong, but it's hard to narrow down without more information on what you have and what errors/behavior you're getting.
You don't have rails.js loading, hence the data-method="delete" isn't having the effect of sending an AJAX post with a _method argument set to "delete".
Your destroy controller action isn't doing what you are expecting.
content is not a local variable referring to an instance of the model you are trying to destroy (note that you would only use the singular content_path if this were a singular resource you were trying to destroy). Are you looking for #content instead maybe? It's hard to say without some context.
And just to clarify for you, the method option is the HTTP method, not the controller method. There is no destroy HTTP method; Rails just uses destroy over delete as a sort of "delete gracefully".
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 recently started to use rails 4 in college and I'm having troubles with deleting a user I created.
It always sais 'Couldn't find User with 'id'=#:' or 'Couldn't find User without Id'.
I looked up a few solutions as this problem seems to be pretty common but nothing worked.
My user list(Index) looks like this and at the end of every line there is the delete button.
<% #user.each do |u| %>
<tr>
<td>
<%= u.username %> <%= u.email%>
<%= link_to 'Delete', user_path(#user), method: :delete, :confirm => 'Are you sure?'%><br>
</td>
</tr>
<% end %>
This is my destroy method
def destroy
#user = User.find(params[:id])
#user.destroy
if #user.destroy
redirect_to root_url, notice: "User deleted."
end
end
And thats the root page - I suppose I made mistakes here somewhere in 'match' but I'm not sure
resources :users
get 'users/index'
get 'users/new'
get 'users/login'
get 'users/resume'
get 'users/userInformation'
get 'users/update'
root 'users#index'
get 'index'=>'users#index'
get 'new'=>'users#new'
get 'login'=>'users#login'
get 'resume'=>'users#resume'
get 'userInformation'=>'users#userInformation'
get 'update'=>'users#update'
match 'users/:id' => 'users#index', :via => :delete
(I'm using Rails4)
Thanks in advance!
Chrizzly
You need to iterate over your collection and pass each instance of that collection into your link handler:
<%= link_to 'Delete', user_path(u), method: :delete, :confirm => 'Are you sure?'%>
Right now you are passing in #user into your user_path so you're passing in the whole collection, which in this case is an ActiveRecord Relation, not the individual User instance.
Maybe try users_path instead of user_path.
You can find all the routes and their helpers by typing rake:routes in the command line.
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.
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.
My route.rb:
map.resources :car_users
car_users_controller.rb:
class CarUsersController < ApplicationController
def index
#car_users = CarUsers.all
end
def show
end
def delete
redirect_to :car_users_path
end
end
I created a delete link in index view:
...
<% #car_users.each do |car_usr| %>
<tr>
<td>
link_to "DELETE IT", delete_car_user_path(car_usr.id)
</td>
</tr>
...
But I got the error:
undefined method `delete_car_user_path' for #<ActionView::Base:0x9d17b40>
Why?
(I am working with Rails v2.3.2)
Because delete_car_user_path isn't a route and I assume you haven't defined it anywhere. If you want a delete link use:
link_to "DELETE IT", car_user_path(car_usr), :method => :delete, :confirm => 'Are you sure ?'
For future reference use rake routes on the command line to get a list of routes.
I do remember an instructor on Lynda.com saying that for whatever reason Rails (I'm on 4.2) does not implement the DELETE route. I feel like there has to be a better way to do this but this worked for me (using RESTful routes):
<%= link_to "DELETE IT", "car_users/#{car_usr.id}/delete", method: :get %>