I have a user page where the user can type and submit posts. I'm using Ajax to allow the user to do this from the user/show page. The problem that I'm having occurs when I try to let the user delete posts. When the user clicks the "remove" link, the post is removed from the page. However, when I reload the page, the post is back. It's not getting destroyed.
I have the same code implemented on the user/edit page in a different context, and that works fine because the post record is destroyed when the form is submitted. However, in this situation where there is no form submitted, I'm not sure how to get this working.
Here's my setup:
:user has_many :posts
:post belongs_to :user
:post belongs_to :post_type
:post_type has_many :posts
User#show:
This is the code for the user to submit the post. This works perfectly.
<% if logged_in? && current_user == @user %>
<% form_tag(:controller => "posts", :action => "create") do %>
<div><%= text_area_tag(:message, nil, :size => "27x3") %></div>
<div><%= submit_tag("Post") %></div>
<div><%= label_tag(:post_type_id, "Update type?", :class => 'typeLabel') %></div>
<div><%= collection_select(@posts, :post_type_id, PostType.all, :id, :name) %></div>
<% end %>
<% end %>
This is the code where the posts are displayed, including the "remove link" at issue:
<% @user.posts.each do |c| %>
<div class="postS">
<div><%=h c.message %></div>
<p><%=h c.post_type.name %></p>
<p>Posted <%=h time_ago_in_words(c.created_at) %> ago</p>
<% if logged_in? && current_user == @user %>
<%= link_to_function "- Delete Post", "if(confirm('Are you sure you want to permanently delete this post?')) $(this).up('.postS').remove()" %>
<% end %>
<%end%>
PostsController
def destroy
@post = Post.find(params[:id])
if @post.destroy
redirect_to :back
else
flash[:notice] = "Post failed to delete."
redirect_to :back
end
end
Let me know if any other information would be helpful. Thanks!
Update 2
I tried using link_to_remote
as explained in the answer below. I agree this is the right solution, but can't get it working. I think it's because of a routes issue.
I have posts set up as a user resource like this:
map.resources :users, :member => { :enable => :put } do |users|
users.resources :posts
end
When I implement the link_to_remote
code provided in the answer, I get a "no method error" exception as follows: undefined method
post_url' for #`
I tried some tweaks that accounted for this, but none of my attempts worked. Any ideas? Am I right that this is related to my route?
UPDATE
The code from the Rails Guides is not working. I tried many variations as well.
The closest I've gotten is this:
<%= link_to_remote "- Delete Post", :url => { :controller => 'posts', :action => 'destroy', :id => @user.posts, :method => :delete }, :confirm => "Are you sure you want to permanetly delete this post?", :success => "$(this).up('.postS').remove();" %>
Using this code, I click the delete link and I am prompted to accept the deletion. After I accept, the post is not deleted on the screen. HOWEVER, it is deleted from the database. Then, when I reload the page, the post is in fact deleted from the screen. So this is mostly working, except that the ajax removal action is now not functioning.
But the code seems wrong. Notice that I wrote: :id => @user.posts
This doesn't seem right to me, but it's the only way I got this code to work at all. Look what this does to the log file:
Processing PostsController#destroy (for 127.0.0.1 at 2009-12-17 02:07:05) [POST]
`Parameters: {"action"=>"destroy", "authenticity_token"=>"GZfPHUc2+qPa6Fj5jNogMyhuB4YUO+KlOdkwjM5NSvw=", "id"=>"12/11", "method"=>"delete", "controller"=>"posts"} `
Notice the id=>"12/11". That's not what I want happening.
When I change the id paramater to :id => @user.post, I get a "no method error." undefined method `post' for #User:0x3ddc20c
When I try :id => user_post_url(@user, @post)
, I get: "user_post_url
failed to generate from [and then it lists all the database column values for this user].
When I try :id => user_posts_url(@user, @posts)
, the page loads. When I click the delete link I'm prompted to accept. Then nothing happens. When I reload the page, the post is still there and never deleted from the database.
That's every variation that I could think of. Any ideas?
Update 3
This is what my routes look like:
user_posts GET /users/:user_id/posts(.:format) {:controller=>"posts", :action=>"index"}
POST /users/:user_id/posts(.:format) {:controller=>"posts", :action=>"create"}
new_user_post GET /users/:user_id/posts/new(.:format) {:controller=>"posts", :action=>"new"}
edit_user_post GET /users/:user_id/posts/:id/edit(.:format) {:controller=>"posts", :action=>"edit"}
user_post GET /users/:user_id/posts/:id(.:format) {:controller=>"posts", :action=>"show"}
PUT /users/:user_id/posts/:id(.:format) {:controller=>"posts", :action=>"update"}
DELETE /users/:user_id/posts/:id(.:format) {:controller=>"posts", :action=>"destroy"}
UPDATE 4
Based on the guidance from ScottD below, my code now looks like this:
<%= link_to_remote "- Delete Post", :url => user_post_url(@user,c), :method => :delete, :confirm => "Are you sure you want to permanently delete this post?", :success => "$(this).up('.postS').remove();" %>
This solves most of my problem, but the javascript remove action is still not getting triggered. In other words, I click the delete link. The post is deleted from the database, but remains on the screen. When I reload the page, the post is gone. So, the problem is that the following part is not getting triggered: :success => "$(this).up('.postS').remove();"
Here's what happens in the log when I click on the delete link as described directly above:
Processing PostsController#destroy (for 127.0.0.1 at 2009-12-17 11:59:18) [DELETE]
Parameters: {"action"=>"destroy", "authenticity_token"=>"ccF1QNCGs9IlvbIYWwmQmcbi7kROgQsTZjM1dM687xA=", "_method"=>"delete", "id"=>"14", "controller"=>"posts", "user_id"=>"1"}
User Columns (3.2ms) SHOW FIELDS FROM `users`
User Load (29.6ms) SELECT * FROM `users` WHERE (`users`.`id` = 1) ORDER BY name
Post Columns (8.7ms) SHOW FIELDS FROM `posts`
Post Load (1.6ms) SELECT * FROM `posts` WHERE (`posts`.`id` = 14)
app/controllers/posts_controller.rb:22:in `destroy'
SQL (0.1ms) BEGIN
app/controllers/posts_controller.rb:23:in `destroy'
Post Destroy (0.5ms) DELETE FROM `posts` WHERE `id` = 14
app/controllers/posts_controller.rb:23:in `destroy'
SQL (0.9ms) COMMIT
app/controllers/posts_controller.rb:23:in `destroy'
Redirected to http://localhost:3000/users/1
Completed in 65ms (DB: 45) | 302 Found [http://localhost/users/1/posts/14]
To me, this all looks good. So I'm not sure why the javascript removal is not working.
When I reload the page, the log shows everything loading normally and the post is gone (as it should be). Any ideas on how I can get the javascript removal to work?
Update #5
Here's what's currently generated in the html based on the link_to_remote
code that I'm using:
<a href="#" onclick="if (confirm('Are you sure you want to permanently delete this post?')) { new Ajax.Request('http://localhost:3000/users/1/posts/18', {asynchronous:true, evalScripts:true, method:'delete', onComplete:function(request){$(this).up('.postS').remove();}, parameters:'authenticity_token=' + encodeURIComponent('ccF1QNCGs9IlvbIYWwmQmcbi7kROgQsTZjM1dM687xA=')}); }; return false;">- Delete Post</a>
Here's what Firebug shows in the console when I click the "delete" text on the page:
POST http://localhost:3000/users/1/posts/18 302 Moved Temporarily
GET http://localhost:3000/users/1 200 OK