after_destroy回调错误"cannot update on new record object"
after_destroy callback error "cannot update on new record object"
我有一个像这样的 after_destroy
回调:
after_destroy :update_max_depth_on_entire_tree
定义为:
def update_max_depth_on_entire_tree
root = self.root
root.check_or_update_max_tree_depth
root.descendants.each { |c|
c.check_or_update_max_tree_depth
}
end
def check_or_update_max_tree_depth
update_columns(max_tree_depth: last_depth)
end
def last_depth
if child_ids.empty?
return depth
else
return children.map{|c| c.last_depth}.max
end
end
每当我尝试删除对象时,我都会收到此错误:
ActiveRecord::ActiveRecordError at /posts/detecting-ramsay-is-offered-ceo-job
cannot update on a new record object
这是服务器日志的样子:
Started DELETE "/posts/detecting-ramsay-is-offered-ceo-job" for 127.0.0.1 at 2015-01-05 09:56:24 -0500
Processing by PostsController#destroy as HTML
Parameters: {"authenticity_token"=>"2xRY+A=", "id"=>"detecting-ramsay-is-offered-ceo-job"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
(2.9ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 3]]
(2.4ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'editor') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 3]]
Post Load (0.9ms) SELECT "posts".* FROM "posts" WHERE "posts"."slug" = 'detecting-ramsay-is-offered-ceo-job' ORDER BY "posts"."id" ASC LIMIT 1
(0.2ms) BEGIN
Post Load (5.2ms) SELECT "posts".* FROM "posts" WHERE (("posts"."ancestry" ILIKE '69/%' OR "posts"."ancestry" = '69'))
Role Load (0.6ms) SELECT "roles".* FROM "roles" WHERE "roles"."resource_id" = AND "roles"."resource_type" = [["resource_id", 69], ["resource_type", "Post"]]
FriendlyId::Slug Load (2.9ms) SELECT "friendly_id_slugs".* FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."sluggable_id" = AND "friendly_id_slugs"."sluggable_type" = ORDER BY "friendly_id_slugs".id DESC [["sluggable_id", 69], ["sluggable_type", "Post"]]
SQL (1.5ms) DELETE FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."id" = [["id", 47]]
SQL (1.2ms) DELETE FROM "posts" WHERE "posts"."id" = [["id", 69]]
Post Load (0.4ms) SELECT "posts"."id" FROM "posts" WHERE "posts"."ancestry" = '69'
(0.2ms) ROLLBACK
Completed 500 Internal Server Error in 281ms
ActiveRecord::ActiveRecordError - cannot update on a new record object:
activerecord (4.1.6) lib/active_record/persistence.rb:272:in `update_columns'
() /app/models/post.rb:122:in `check_or_update_max_tree_depth'
() /app/models/post.rb:130:in `update_max_depth_on_entire_tree'
如何调用此方法或实现我想要实现的目标(即在删除 1 个节点时更新树上所有节点的属性)而不出现此错误?
编辑 1
我的路线是这样的:
mark_as_published_post_path PUT /posts/:id/mark_as_published(.:format) posts#mark_as_published
mark_as_unpublished_post_path PUT /posts/:id/mark_as_unpublished(.:format) posts#mark_as_unpublished
posts_path GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post_path GET /posts/new(.:format) posts#new
edit_post_path GET /posts/:id/edit(.:format) posts#edit
post_path GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
status_path GET /:status(.:format) posts#status {:status=>/confirmed|unconfirmed|corroborated/}
GET /posts/:id(.:format) redirect(301, /%{id})
GET /:friendly_id(.:format) posts#show
GET /posts/:friendly_id(.:format) posts#show
GET /rbt/:name(.:format) redirect(301)
GET /:name(.:format) posts#show
root_path GET / posts#index
这就是我的 PostController#Destroy
的样子:
def destroy
@post = Post.find(params[:id])
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Report was successfully destroyed.' }
format.json { head :no_content }
end
end
编辑 2
我认为问题在于这部分代码:
def check_or_update_max_tree_depth
update_columns(max_tree_depth: last_depth)
end
错误似乎是说它在链中的某处遇到了新记录,并且无法在作为新记录的对象上执行 update_columns(max_tree_depth: last_depth)
。
我该如何解决这个问题?
这个问题已经变得有点难以掌握,但我会试一试。 . .
您的最新更新表明您的问题在于 update_columns
对新记录不起作用。为什么不使用 update_attributes` 呢?
变化:
def check_or_update_max_tree_depth
update_columns(max_tree_depth: last_depth)
end
至:
def check_or_update_max_tree_depth
update_attributes(max_tree_depth: last_depth)
end
我发现了一个与 update_columns
2012 年以来无法处理新记录的问题相关的讨论,其中可能包含一些信息,可以帮助您重组给您带来麻烦的应用程序部分:https://github.com/rails/rails/issues/7226
更新:
您已经回答了这个问题,但只是为了完整主义者的缘故在这里注明。 . .
另一种解决方案是简单地向您的 update_columns
方法添加一个条件,以检查对象是否为 new_record?
:
if new_record?
return
else
update_column(:max_tree_depth, last_depth)
end
我最终通过做一些事情弄明白了。像这样将我的 update_column(max_tree_depth: last_depth)
包裹在 new_record?
支票中:
def check_or_update_max_tree_depth
if new_record?
return
else
update_column(:max_tree_depth, last_depth)
end
end
解决了那个错误。
我遇到的另一个错误是,每当我的回调遇到作为根记录的记录时,因为我在祖先中使用 :adopt
孤儿策略来确定如何处理已删除的记录帖子,它正在从 post.children
创建一个新记录并将它们分配给 root 并将所有内容都扔进 wack。
所以我只是像这样修改了我的代码:
def update_max_depth_on_entire_tree
if max_tree_depth <= 0
return
else
root = self.root
root.check_or_update_max_tree_depth
root.descendants.each { |c|
c.check_or_update_max_tree_depth
}
end
end
这似乎已经做到了。
我有一个像这样的 after_destroy
回调:
after_destroy :update_max_depth_on_entire_tree
定义为:
def update_max_depth_on_entire_tree
root = self.root
root.check_or_update_max_tree_depth
root.descendants.each { |c|
c.check_or_update_max_tree_depth
}
end
def check_or_update_max_tree_depth
update_columns(max_tree_depth: last_depth)
end
def last_depth
if child_ids.empty?
return depth
else
return children.map{|c| c.last_depth}.max
end
end
每当我尝试删除对象时,我都会收到此错误:
ActiveRecord::ActiveRecordError at /posts/detecting-ramsay-is-offered-ceo-job
cannot update on a new record object
这是服务器日志的样子:
Started DELETE "/posts/detecting-ramsay-is-offered-ceo-job" for 127.0.0.1 at 2015-01-05 09:56:24 -0500
Processing by PostsController#destroy as HTML
Parameters: {"authenticity_token"=>"2xRY+A=", "id"=>"detecting-ramsay-is-offered-ceo-job"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
(2.9ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 3]]
(2.4ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'editor') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 3]]
Post Load (0.9ms) SELECT "posts".* FROM "posts" WHERE "posts"."slug" = 'detecting-ramsay-is-offered-ceo-job' ORDER BY "posts"."id" ASC LIMIT 1
(0.2ms) BEGIN
Post Load (5.2ms) SELECT "posts".* FROM "posts" WHERE (("posts"."ancestry" ILIKE '69/%' OR "posts"."ancestry" = '69'))
Role Load (0.6ms) SELECT "roles".* FROM "roles" WHERE "roles"."resource_id" = AND "roles"."resource_type" = [["resource_id", 69], ["resource_type", "Post"]]
FriendlyId::Slug Load (2.9ms) SELECT "friendly_id_slugs".* FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."sluggable_id" = AND "friendly_id_slugs"."sluggable_type" = ORDER BY "friendly_id_slugs".id DESC [["sluggable_id", 69], ["sluggable_type", "Post"]]
SQL (1.5ms) DELETE FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."id" = [["id", 47]]
SQL (1.2ms) DELETE FROM "posts" WHERE "posts"."id" = [["id", 69]]
Post Load (0.4ms) SELECT "posts"."id" FROM "posts" WHERE "posts"."ancestry" = '69'
(0.2ms) ROLLBACK
Completed 500 Internal Server Error in 281ms
ActiveRecord::ActiveRecordError - cannot update on a new record object:
activerecord (4.1.6) lib/active_record/persistence.rb:272:in `update_columns'
() /app/models/post.rb:122:in `check_or_update_max_tree_depth'
() /app/models/post.rb:130:in `update_max_depth_on_entire_tree'
如何调用此方法或实现我想要实现的目标(即在删除 1 个节点时更新树上所有节点的属性)而不出现此错误?
编辑 1
我的路线是这样的:
mark_as_published_post_path PUT /posts/:id/mark_as_published(.:format) posts#mark_as_published
mark_as_unpublished_post_path PUT /posts/:id/mark_as_unpublished(.:format) posts#mark_as_unpublished
posts_path GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post_path GET /posts/new(.:format) posts#new
edit_post_path GET /posts/:id/edit(.:format) posts#edit
post_path GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
status_path GET /:status(.:format) posts#status {:status=>/confirmed|unconfirmed|corroborated/}
GET /posts/:id(.:format) redirect(301, /%{id})
GET /:friendly_id(.:format) posts#show
GET /posts/:friendly_id(.:format) posts#show
GET /rbt/:name(.:format) redirect(301)
GET /:name(.:format) posts#show
root_path GET / posts#index
这就是我的 PostController#Destroy
的样子:
def destroy
@post = Post.find(params[:id])
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Report was successfully destroyed.' }
format.json { head :no_content }
end
end
编辑 2
我认为问题在于这部分代码:
def check_or_update_max_tree_depth
update_columns(max_tree_depth: last_depth)
end
错误似乎是说它在链中的某处遇到了新记录,并且无法在作为新记录的对象上执行 update_columns(max_tree_depth: last_depth)
。
我该如何解决这个问题?
这个问题已经变得有点难以掌握,但我会试一试。 . .
您的最新更新表明您的问题在于 update_columns
对新记录不起作用。为什么不使用 update_attributes` 呢?
变化:
def check_or_update_max_tree_depth
update_columns(max_tree_depth: last_depth)
end
至:
def check_or_update_max_tree_depth
update_attributes(max_tree_depth: last_depth)
end
我发现了一个与 update_columns
2012 年以来无法处理新记录的问题相关的讨论,其中可能包含一些信息,可以帮助您重组给您带来麻烦的应用程序部分:https://github.com/rails/rails/issues/7226
更新:
您已经回答了这个问题,但只是为了完整主义者的缘故在这里注明。 . .
另一种解决方案是简单地向您的 update_columns
方法添加一个条件,以检查对象是否为 new_record?
:
if new_record?
return
else
update_column(:max_tree_depth, last_depth)
end
我最终通过做一些事情弄明白了。像这样将我的 update_column(max_tree_depth: last_depth)
包裹在 new_record?
支票中:
def check_or_update_max_tree_depth
if new_record?
return
else
update_column(:max_tree_depth, last_depth)
end
end
解决了那个错误。
我遇到的另一个错误是,每当我的回调遇到作为根记录的记录时,因为我在祖先中使用 :adopt
孤儿策略来确定如何处理已删除的记录帖子,它正在从 post.children
创建一个新记录并将它们分配给 root 并将所有内容都扔进 wack。
所以我只是像这样修改了我的代码:
def update_max_depth_on_entire_tree
if max_tree_depth <= 0
return
else
root = self.root
root.check_or_update_max_tree_depth
root.descendants.each { |c|
c.check_or_update_max_tree_depth
}
end
end
这似乎已经做到了。