Rails 回调 before_update 的误区

torvaldsdb · 2016年09月21日 · 最后由 hging 回复于 2016年09月24日 · 2808 次阅读

before_update

如果想在该回调函数中重新更新对象的属性,这时候要避免使用 update 或者 update_attributes, 换一个方法使用 update_column

update_column这个方法提供

  • Validations are skipped.(跳过验证)
  • Callbacks are skipped.(跳过回调)
  • updated_at/updated_on are not updated.(两个字段不再更新)

这样可以避免 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?这种方法。判断是在更新还是创建。

#8 楼 @hging 需要处理对象的 id,也就是一个中间表需要该表的 id 作为外键,如果不是 after_create 该对象的 id 是 nil 无法处理外键的问题

#9 楼 @torvaldsdb 一个中间表的话 处理可以直接用 has_many 这种 model 关联关系进行创建啊 不需要手工处理 id 啊

需要 登录 后方可回复, 如果你还没有账号请 注册新账号