如果记录是全新的,我如何执行 'after_save',如果不是,我如何执行 `before_save`?
How do I execute an 'after_save' if a record is brand new, but a `before_save` if it isn't?
我有一个before_save
要求记录在created/saved之前。
如果记录不是 new
,我是否可以执行 before_save
,如果是,则执行 after_save
?
编辑 1
这是我的方法和回调:
after_save :check_or_update_max_tree_depth
def check_or_update_max_tree_depth
self.max_tree_depth = self.last_depth
end
def last_depth
if child_ids.empty?
return root.max_tree_depth
else
return children.map{|c| c.last_depth}.max
end
end
新记录创建后,不保存max_tree_depth
属性。这是刚刚创建的新记录的示例:
[155] pry(main)> p = Post.last
Post Load (1.9ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT 1
=> #<Post id: 63, title: "JPS counter sues", photo: nil, body: "JPS has officially filed a countersuit on crashees...", created_at: "2015-01-05 05:30:39", updated_at: "2015-01-05 05:30:39", user_id: 3, ancestry: "46/54/59", file: nil, status: 1, slug: "jps-counter-sues", publication_status: 1, has_eyewitness: false, youtube_embed_code: "", soundcloud_embed_code: "", ancestry_depth: 3, max_tree_depth: nil>
[156] pry(main)> p.last_depth
Post Load (0.5ms) SELECT "posts"."id" FROM "posts" WHERE "posts"."ancestry" = '46/54/59/63'
Post Load (1.0ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = LIMIT 1 [["id", 46]]
=> 4
[157] pry(main)> p.child_ids
Post Load (1.5ms) SELECT "posts"."id" FROM "posts" WHERE "posts"."ancestry" = '46/54/59/63'
=> []
[158] pry(main)> p.root.max_tree_depth
Post Load (1.5ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = LIMIT 1 [["id", 46]]
=> 4
[159] pry(main)> p.max_tree_depth
=> nil
请注意,其他一切似乎都返回了正确的值。只是每当创建一条新记录时,它不会保存它。
如果我使用 before_save
,它会正确更新属性 - 但仅限于现有记录。在以前未保存的全新记录上,ancestry gem
会引起不适。
以下应该可以完成您想要的:
before_save :method_name
after_save :method_name
private
def method_name
if new_record? || @already_ran
@already_ran = nil # using 'remove_instance_variable' would be better
return
end
# your method's original code
@already_ran = true # pick a better variable name
end
@already_ran
只是为了确保在保存之前和之后不会调用相同的方法。如果在保存之前和之后两次 运行 它是安全的,那么你可以像这样简化事情:
before_save :method_name
after_save :method_name
private
def method_name
return if new_record?
# your method's original code
end
或者,根据您的使用情况,您可以只保留 after_save
并完全删除 before_save
。但我假设您已经考虑过其他简化选项,例如有一个 after_save
或 after_create
回调。
您所要做的就是重新加载持久化对象
after_save :check_or_update_max_tree_depth
def check_or_update_max_tree_depth
self.reload
self.max_tree_depth = self.last_depth
self.save
end
def last_depth
if child_ids.empty?
return root.max_tree_depth
else
return children.map{|c| c.last_depth}.max
end
end
我有一个before_save
要求记录在created/saved之前。
如果记录不是 new
,我是否可以执行 before_save
,如果是,则执行 after_save
?
编辑 1
这是我的方法和回调:
after_save :check_or_update_max_tree_depth
def check_or_update_max_tree_depth
self.max_tree_depth = self.last_depth
end
def last_depth
if child_ids.empty?
return root.max_tree_depth
else
return children.map{|c| c.last_depth}.max
end
end
新记录创建后,不保存max_tree_depth
属性。这是刚刚创建的新记录的示例:
[155] pry(main)> p = Post.last
Post Load (1.9ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT 1
=> #<Post id: 63, title: "JPS counter sues", photo: nil, body: "JPS has officially filed a countersuit on crashees...", created_at: "2015-01-05 05:30:39", updated_at: "2015-01-05 05:30:39", user_id: 3, ancestry: "46/54/59", file: nil, status: 1, slug: "jps-counter-sues", publication_status: 1, has_eyewitness: false, youtube_embed_code: "", soundcloud_embed_code: "", ancestry_depth: 3, max_tree_depth: nil>
[156] pry(main)> p.last_depth
Post Load (0.5ms) SELECT "posts"."id" FROM "posts" WHERE "posts"."ancestry" = '46/54/59/63'
Post Load (1.0ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = LIMIT 1 [["id", 46]]
=> 4
[157] pry(main)> p.child_ids
Post Load (1.5ms) SELECT "posts"."id" FROM "posts" WHERE "posts"."ancestry" = '46/54/59/63'
=> []
[158] pry(main)> p.root.max_tree_depth
Post Load (1.5ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = LIMIT 1 [["id", 46]]
=> 4
[159] pry(main)> p.max_tree_depth
=> nil
请注意,其他一切似乎都返回了正确的值。只是每当创建一条新记录时,它不会保存它。
如果我使用 before_save
,它会正确更新属性 - 但仅限于现有记录。在以前未保存的全新记录上,ancestry gem
会引起不适。
以下应该可以完成您想要的:
before_save :method_name
after_save :method_name
private
def method_name
if new_record? || @already_ran
@already_ran = nil # using 'remove_instance_variable' would be better
return
end
# your method's original code
@already_ran = true # pick a better variable name
end
@already_ran
只是为了确保在保存之前和之后不会调用相同的方法。如果在保存之前和之后两次 运行 它是安全的,那么你可以像这样简化事情:
before_save :method_name
after_save :method_name
private
def method_name
return if new_record?
# your method's original code
end
或者,根据您的使用情况,您可以只保留 after_save
并完全删除 before_save
。但我假设您已经考虑过其他简化选项,例如有一个 after_save
或 after_create
回调。
您所要做的就是重新加载持久化对象
after_save :check_or_update_max_tree_depth
def check_or_update_max_tree_depth
self.reload
self.max_tree_depth = self.last_depth
self.save
end
def last_depth
if child_ids.empty?
return root.max_tree_depth
else
return children.map{|c| c.last_depth}.max
end
end