如果想在该回调函数中重新更新对象的属性,这时候要避免使用 update 或者 update_attributes, 换一个方法使用 update_column
update_column这个方法提供
这样可以避免 before_update 的死循环。
save(validate: false)
。。。然后就一堆脏数据。。 其实讲道理在 before_update 里面不应该直接更新数据 直接指定就好。然后后面会自动更新的。这样即保证了数据的完整性又实现了效果。
after_save 也有个不太容易被注意的小坑
如果 after_save 里用了 sidekiq,那么可能该数据被 commit 到数据库前 sidekiq 就会去取它
#1 楼 @hging 直接指定 具体一下嘛 我最后用 update_column 解决的...也觉得很不妥。不过放弃安全问题,可用非最好。
#3 楼 @torvaldsdb 比如你直接这么写
def set_username self.username = "xxxx" end
这样就行了啊。没必要在 before_update 的时候直接 update
before_update 中去 update 这条数据本身么?按 4 楼那样赋值就好了 另外我有点好奇 update_column 应该会直接写数据库然后返回新的对象吧,你这样是不是会有两条数据库写入操作?
#2 楼 @adamshen 这个问题是不是 after_save 和 after_commit 行为差异的那个坑,之前看文章提到 5 里会修复,也不知道修了没
#4 楼 @hging
我用到 after_create 与 before_update,然后两个方法里面重复代码太多我就想复用一下重复的代码,然后更新了相同的属性。你提出来的那种直接赋值,不能在 after_create 中良好嵌用。所以我曲线救国的选用了 update_column.
#5 楼 @IChou 好像是个问题...我还是测试一下吧
#6 楼 @torvaldsdb 所以。为什么会同时使用 after_create 与 before_update 并且会有重复代码。这个是比较关键的问题。要理清楚逻辑,尽可能简化,甚至说可以在共用代码中使用new_record?这种方法。判断是在更新还是创建。
new_record?
#8 楼 @hging 需要处理对象的 id,也就是一个中间表需要该表的 id 作为外键,如果不是 after_create 该对象的 id 是 nil 无法处理外键的问题
#9 楼 @torvaldsdb 一个中间表的话 处理可以直接用 has_many 这种 model 关联关系进行创建啊 不需要手工处理 id 啊