2

我在 rails 中使用 default_scope 来吸出任何具有 is_deleted = true 值的东西(任何具有该值的东西都不应显示,但我仍然想将该行保留在数据库中)。但是有一个控制器操作实际上应该取消删除某些内容(设置 is_deleted = false),但它失败了,因为正在应用 default_scope。据我了解,default_scope 仅在选择/创建记录时应用,但在更新时不应用(来源:http ://api.rubyonrails.org/classes/ActiveRecord/Scopeing/Default/ClassMethods.html )。

在创建/构建记录时也会应用 default_scope。更新记录时不应用它。

我知道我可以使用 .unscoped 方法,但这似乎违反直觉。我误解了文档吗?

应用程序/模型/post.rb

class Post < ActiveRecord::Base
  default_scope where(:is_deleted => false)

应用程序/控制器/posts_controller.rb

class PostsController < ApplicationController
def undelete
  @post = Post.update(params[:id], :is_deleted => false)
  render :action => :success if @post.save
end

错误

找不到 id=1 的帖子 [WHERE "posts"."is_deleted" = 'f']

4

2 回答 2

4

您提到的文档中的行 ( The default_scope is also applied while creating/building a record. It is not applied while updating a record.) - 表示 default_scope 属性应用于构建/创建的所有模型:

在您的情况下,所有新记录的is_deleted属性都将设置为 false

但是在更新时,如果您从数据库中获取记录,请更改一个属性(例如title),然后调用save- 该is_deleted属性不会被强制为false,因为它发生在创建时。

但是update你使用的方法(你可以在这里查看)只是find在内部使用,它总是使用default_scope

解决方案就是使用unscoped方法

class PostsController < ApplicationController
def undelete
  @post = Post.unscoped.update(params[:id], :is_deleted => false)
  render :action => :success if @post.save
end
于 2012-12-18T17:13:10.720 回答
1

我认为您对语义很感兴趣。Rails 必须先找到您的记录,然后才能更新它。要让 Rails 找到记录,您需要使用 .unscoped 方法。要查看 Rails 如何应用范围值,您可以:

raise Post.find(:id => id, :is_deleted => true).to_sql

您应该会看到如下内容:

SELECT * FROM posts WHERE `id`=123 AND `is_deleted` = true AND `is_deleted` = false

.unscoped 方法告诉 Rails 不要应用最后一个条件。Rails 不会跳过默认范围,即使您为同一字段提供了附加条件。

于 2012-12-18T17:06:08.007 回答