【问题标题】:Best Practice for Bulk Update in Controller控制器中批量更新的最佳实践
【发布时间】:2011-12-19 10:32:28
【问题描述】:

我想知道在控制器中允许批量编辑/更新的最佳做法是什么。我真的找不到关于这个主题的文章或指南。

【问题讨论】:

  • 运行批量操作需要一段时间,并可能导致您的应用超时。最好的方法是使用延迟作业来运行批量操作。 railscasts.com/episodes/171-delayed-job
  • 我对异步运行它不感兴趣。我已经使用 AJAX 从 Javascript 调用它。扩展现在不是问题。

标签: ruby ruby-on-rails-3 model-view-controller rest


【解决方案1】:

我看到您使用 REST 标记了您的问题。

要以 REST 方式执行此操作,您需要将集合或更新本身视为资源。

假设您正在使用 Product 对象。

您可能会 PUT 到 /product_batches/[some identifier],这将调用 ProductBatchesController#update,但随后您会想知道 [some identifier] 中的内容。您可以将 ProductBatch 设为 singular resource,然后就不需要 id。

最好是 POST 到 /product_bulk_updates,它会调用 ProductBulkUpdatesController#create

class ProductBulkUpdatesController < ApplicationController

  def create
    # your magic here
    # - update_all if you are making the same change to all Products
    # - looping through the hashes in params[products] if you are passing in distinct changes to each.
  end

end

这是另一个线程: Bulk Collection Manipulation through a REST (RESTful) API

【讨论】:

  • 我觉得这很棒。
  • 很好的答案!为什么你用 batch 这个词来命名第一个控制器,而用 bulk 来命名第二个控制器?您认为 ProductBulksController 不正确吗?我不是英语母语,在这种情况下,我永远不知道哪个词最合适。
  • 我礼貌地不同意。将操作定义为资源并不是一种非常 RESTful 的方法。您要做的是更新集合资源,该资源已由/products 定义(坚持示例)。所以PUT|PATCH /products 似乎更合适(取决于它是否应该是幂等的)。拥有代表操作的资源(例如您的示例中的更新)与 REST 方法冲突。此外,它建议您可以创建、删除和更新“更新”。
【解决方案2】:

我认为没有标准的方法。您可以使用update_attributes(以 PostsController 为例):

def update_bulk
  @posts = Post.where(:id => params[:ids])

  # wrap in a transaction to avoid partial updates (and move to the model)
  if @posts.all? { |post| post.update_attributes(params[:post]) }
    redirect_to(posts_url)
  else
    redirect_to(:back)
  end
end

或者使用update_all,但是注意回调和验证都不会被调用:

def update_bulk
  Post.where(:id => params[:ids]).update_all(params[:post])
  redirect_to(posts_url)
end

【讨论】:

  • 这与我已经在做的类似。很高兴我不是唯一一个。
  • 我更喜欢 Rails 3 ActiveRecord::Relation#update_all 构造一个实际的 SQL 更新语句来使用......当它适用时。我只希望我们早点拥有它。 :)
  • @coderjoe:添加了带有 update_all 的 sn-p。但是,update_all 不会触发回调/验证。
【解决方案3】:

如果您有幸在 Rails 3 中工作,那么您应该确保查看 Rails 2 中的 ActiveRecord::Relation#update_all 或 ActiveRecord::Base#update_all:

构造单个 SQL 更新语句比执行完整的 SQL 往返更新元素要好得多。

重要提示:这确实是使用 SQL 更新语句进行的批量更新。它不会实例化任何 ActiveRecord 对象,因为更新纯粹在 SQL 中执行。因此不会调用 ActiveRecord 回调和验证。

来自上述 URL 的示例:

# Update all customers with the given attributes
Customer.update_all :wants_email => true

# Conditions from the current relation also works
Book.where('title LIKE ?', '%Rails%').update_all(:author => 'David')

注意:据我从 Internet 上的帖子得知,此功能在 Rails 3.0.3、3.0.7 - 3.0.9 中处于错误和损坏之间。

我直到 3.1.0 才发现这个功能,所以我无法证实。

【讨论】:

  • 我现在使用 Rails 3.0.x。 #update_all 似乎忽略了范围,只是更新了该模型的所有记录。我想这就是你所说的。
  • 是的,这就是我所指的。感谢您添加注释!这是人们看到的非常重要的一个。 :)
  • FWIW 在 Rails 2 中存在类似的方法......我只是不知道。添加对我的描述的引用。
【解决方案4】:

对@Robert Head 的回答做了一些小的补充。在 Rails 官方参考中有一个章节“什么是 REST?http://guides.rubyonrails.org/v2.3.11/routing.html#what-is-rest

本章参考REST's author Roy Fielding 的博士论文。在本文的“5.2.1.1 资源和资源标识符”章节中我们可以看到:

http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_2_1_1

REST 中信息的关键抽象是资源。任何 可以命名的信息可以是资源:文档或图像, 临时服务(例如“洛杉矶今天的天气”),a 其他资源的集合,一个非虚拟对象(例如一个人), 等等。

因此,在这里定义一个 ProductCollection 资源 - 具有 7 个自己的 RESTful 操作 - 将很好地融入整个 REST 概念。

【讨论】:

    【解决方案5】:

    这个我没试过,也不是真正的模型级批量操作,不过还是挺有意思的。

    batch_api gem 允许一个人累积请求并一次性发送它们。 Facebook 也有类似的机制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-29
      • 1970-01-01
      • 2018-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-09
      相关资源
      最近更新 更多