如何在给定id列表的情况下更新所有模型的布尔属性?

时间:2013-01-15 05:54:30

标签: ruby-on-rails ruby-on-rails-3 rails-activerecord

我正在做类似于这些railscast剧集的事情:

http://railscasts.com/episodes/165-edit-multiple

http://railscasts.com/episodes/52-update-through-checkboxes

问题是那些只是试图修改所选模型。我需要更新每一个模型。

我发现的第一件事是id not in ()并没有像我预期的那样回馈所有内容,所以我不得不为空列表做一个特例。

此代码有效,但看起来并不干净。至少我应该能够将正常情况合并为一行。

def update_published
  if params[:book_ids].empty?
    Book.update_all(published: false)
  else
    Book.where(id: params[:book_ids]).update_all(published: true)
    Book.where("id not in (?)", params[:book_ids]).update_all(published: false)
  end
  redirect_to books_path
end

任何改进的想法都将受到赞赏。

3 个答案:

答案 0 :(得分:2)

为什么不执行以下操作:

def update_published
  Book.update_all(published: false)
  Book.where(id: params[:book_ids]).update_all(published: true)
  redirect_to books_path
end

它会更快,而且非常直接和干净。

答案 1 :(得分:0)

我终于明白了。

def update_published
  Book.update_all(["published = id in (?)", params[:book_ids]])
  redirect_to books_path
end

我昨天试图做类似的事情,但它仍然给我一个错误,其中?没有填写,而且它在我的ID上做where。今天,我终于意识到我需要将两个参数都包装成一个数组。

关于这一点的一个奇怪的警告是它搞砸了我的一些规格。我正在检查是否错误,但是它给了零。在数据库中,它似乎设置为false。我将规范从be(false)更改为be_false,现在感觉很安全。

答案 2 :(得分:0)

你可以这样做:

def update_published
    Book.transaction do
      Book.update_all(published: false)
      Book.scoped.find(params[:book_ids]).update_all(published: true) #Should be Lazyloaded. Testing Now
    end
end

因为它是一个交易,所以它会非常快。另请注意我如何使用“find”,而不是“where”。在我看来这更好。使代码稍微清晰。

注意:我会怀疑为什么每次都需要更新每个图书实体。要逐一跟踪出版的书籍是不是更聪明?如果您需要在每次更新一本书时传递每本书ID,您一定会遇到麻烦。该解决方案的可扩展性不高。

你应该拥有的是:

def publish_book(book)
  book.published = true;
  book.save!
end

甚至更好:

#Book.rb
def publish
  self.published = true
  self.save #not 100% sure you need this. Anyone?
end

每当你能(许多人同意)应该遵循“瘦瘦的控制器,胖模型”的方法。这意味着您基本上将尽可能多的代码放在模型类中,而不是在任何其他地方放置它。