【问题标题】:Deleting Records with Ajax in Rails在 Rails 中使用 Ajax 删除记录
【发布时间】:2009-12-16 05:11:07
【问题描述】:

我有一个用户页面,用户可以在其中键入和提交帖子。我正在使用 Ajax 来允许用户从用户/显示页面执行此操作。当我尝试让用户删除帖子时,会出现我遇到的问题。当用户单击“删除”链接时,该帖子将从页面中删除。但是,当我重新加载页面时,帖子又回来了。它不会被摧毁。

我在不同上下文的用户/编辑页面上实现了相同的代码,并且工作正常,因为在提交表单时帖子记录被破坏。但是,在这种没有提交表单的情况下,我不知道如何让它工作。

这是我的设置:

:user has_many :posts
:post belongs_to :user
:post belongs_to :post_type
:post_type has_many :posts

用户#show:
这是用户提交帖子的代码。这完美地工作。

<% 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 %>

这是显示帖子的代码,包括有问题的“删除链接”:

<% @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

如果有任何其他信息有帮助,请告诉我。谢谢!

更新 2

我尝试使用link_to_remote,如下面的答案所述。我同意这是正确的解决方案,但无法使其正常工作。我认为这是因为路线问题。

我将帖子设置为这样的用户资源:

map.resources :users, :member => { :enable => :put } do |users|
  users.resources :posts
end  

当我实现答案中提供的link_to_remote 代码时,我得到一个“无方法错误”异常,如下所示:undefined methodpost_url' for #`

我尝试了一些调整来解决这个问题,但我的尝试都没有奏效。有任何想法吗?我对这与我的路线有关吗?

更新

Rails 指南中的代码不起作用。我也尝试了很多变体。

我得到的最接近的是:

<%= 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();" %>  

使用此代码,我单击删除链接,系统会提示我接受删除。我接受后,屏幕上的帖子不会被删除。但是,它已从数据库中删除。然后,当我重新加载页面时,该帖子实际上已从屏幕上删除。所以这主要是有效的,除了 ajax 删除操作现在不起作用。

但代码似乎错误。请注意我写了: :id => @user.posts

这对我来说似乎不对,但这是我让这段代码工作的唯一方法。看看这对日志文件做了什么:
处理 PostsController#destroy(2009-12-17 02:07:05 为 127.0.0.1)[POST]

`Parameters: {"action"=>"destroy", "authenticity_token"=>"GZfPHUc2+qPa6Fj5jNogMyhuB4YUO+KlOdkwjM5NSvw=", "id"=>"12/11", "method"=>"delete", "controller"=>"posts"}  `

注意 id=>“12/11”。那不是我想要发生的事情。

当我将 id 参数更改为 :id => @user.post 时,我收到“无方法错误”。 #User:0x3ddc20c 的未定义方法“post”

当我尝试:id =&gt; user_post_url(@user, @post) 时,我得到:"user_post_url 无法从 [然后它列出该用户的所有数据库列值] 生成。

当我尝试:id =&gt; user_posts_url(@user, @posts) 时,页面会加载。当我单击删除链接时,系统会提示我接受。然后什么也没有发生。当我重新加载页面时,帖子仍然存在并且从未从数据库中删除。

这是我能想到的所有变化。有什么想法吗?

更新 3

这是我的路线的样子:

    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"}

更新 4

根据下面 ScottD 的指导,我的代码现在如下所示:

<%= 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();" %>  

这解决了我的大部分问题,但仍然没有触发 javascript 删除操作。换句话说,我点击删除链接。该帖子已从数据库中删除,但仍保留在屏幕上。当我重新加载页面时,帖子消失了。所以,问题在于以下部分没有被触发: :success => "$(this).up('.postS').remove();"

当我单击上面直接描述的删除链接时,日志中会发生以下情况:

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]  

对我来说,这一切看起来都不错。所以我不确定为什么 javascript 删除不起作用。

当我重新加载页面时,日志显示一切正常加载并且帖子消失了(应该是这样)。关于如何让 javascript 删除工作的任何想法?

更新 #5

这是当前基于我正在使用的link_to_remote 代码在 html 中生成的内容:

<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>  

当我单击页面上的“删除”文本时,Firebug 在控制台中显示的内容如下:

POST http://localhost:3000/users/1/posts/18  302 Moved Temporarily  
GET  http://localhost:3000/users/1 200 OK

【问题讨论】:

  • 由于您使用的是嵌套资源,因此您的 url 看起来更像 user_post_url(@user,@post) 。查看 Rails 嵌套资源文档。此外,您可以从 RAILS_ROOT 在命令行上运行 rake routes 以打印出所有路由。
  • 查看您上面的代码,我看到您正在循环浏览用户的帖子并为帖子设置一个名为“c”的变量。所以在url中你需要做 user_post_url(@user, c)
  • 谢谢,斯科特。这几乎让我到了那里。我实施了您的指导并对问题添加了更新以尝试隔离最终问题。有什么想法吗?

标签: ruby-on-rails ajax


【解决方案1】:

问题是您使用的是link_to_function,它只调用一个Javascript函数,它不会向您的应用发布任何内容。如果你想做 Ajax,试试link_to_remote。这将进行 AJAX 调用,然后它允许您基于回调挂钩(如 :success:complete)调用 javascript。

基于您的示例的示例:

<% if logged_in? && current_user == @user %>
  <%= link_to_remote "- Delete Post", :url => user_post_url(@user,c, :format => :json), :method => :delete  , :confirm => "Are you sure you want to permanetly delete this post?", :success => "$(this).up('.postS').remove();" %>                                                      
<% end %> 

查看Rails API docs for link_to_remote 了解更多示例。

您还需要更新您的 Post Controller 以响应来自 Ajax 的删除请求。我使用新的 json gem 来渲染 json。

def destroy
  @post = Post.find(params[:id])
  respond_to do |format|
    if @post.destroy
      format.html { redirect_to :back }
      format.json { :success => true }.as_json
    else
      flash[:notice] = "Post failed to delete."
      format.html { redirect_to :back }
      format.json { :success => false }.as_json
    end
  end
end

已更新以反映相关的嵌套路由。

【讨论】:

  • OP 在这里要理解的重要一点是,OP 的方法仅从用户计算机上的浏览器中删除帖子,而不是从服务器上的数据库中删除。
  • 谢谢。有道理,但我在实施时遇到了一些麻烦。我想我知道为什么,但不能让它工作。查看原始问题中的更新。
  • 谢谢。我尝试了许多实现,但仍然不完全存在。我更新了问题以解释我试图做什么。有什么想法吗?
  • 我想可能是控制器问题?我是否需要在posts控制器的destroy方法中包含一些不存在的东西?
  • 感谢斯科特的更新。我认为这是一个控制器问题,但无法使其工作。这个 Json 东西在我头上。我需要一段时间才能弄清楚如何让这一切正常工作。
【解决方案2】:

如果它对你有帮助,我现在在我的应用程序中遇到了类似的问题,直到现在我已经追踪到一个事实,除了

:success => "$(this).up('.postS').remove();"

link_to_remote 的一部分没有像想象的那样工作。由于某种原因,它在 DOM 中找不到正确的 div。

我并不是说这是你的问题,但它可能会让你走上正轨。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    • 2013-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-12
    相关资源
    最近更新 更多