【问题标题】:What is the difference between `before_create` and `after_create` and when to use which?`before_create` 和 `after_create` 有什么区别,什么时候使用?
【发布时间】:2014-04-09 04:14:32
【问题描述】:

我知道 before_create 在对象被转换到数据库之前被调用,而 after_create 被调用之后。

只有在对象无法满足数据库常量(唯一键等)时才会调用 before_create 而不会调用 after_create。除此之外,我可以将 after_create 中的所有逻辑放在 before_create 中

我错过了什么吗?

【问题讨论】:

  • 请详细说明Other that that I can place all the logic from after_create in before_create,以便我们适当回答。

标签: ruby-on-rails ruby-on-rails-3 rails-activerecord


【解决方案1】:

为了理解这两个回调,首先你需要知道这两个是什么时候被调用的。下面是 ActiveRecord 回调排序:

(-) 保存

(-) 有效

(1) before_validation

(-) 验证

(2) after_validation

(3) before_save

(4) before_create

(-) 创建

(5) after_create

(6) after_save

(7) after_commit

你可以看到before_create是在after_validation之后调用的,简单来说,这个回调是在你的ActiveRecord通过验证后调用的。这个before_create 通常用于在验证后设置一些额外的属性。

现在转到after_create,您可以看到这是在记录持久存储到数据库后创建的。人们通常使用它来执行发送通知、日志记录等操作。

对于这个问题,你应该什么时候使用它?答案是“你根本不应该使用它”。 ActiveRecord 回调是反模式的,经验丰富的 Rails 开发人员认为它有代码味道,您可以通过使用 Service 对象来实现所有这些。这是一个简单的例子:

class Car < ActiveRecord::Base
  before_create :set_mileage_to_zero
  after_create  :send_quality_report_to_qa_team
end

can be rewritten in

# app/services/car_creation.rb

class CarCreation

  attr_reader :car

  def initialize(params = {})
    @car = Car.new(params)
    @car.mileage = 0
  end

  def create_car
    if car.save
      send_report_to_qa_team
    end 
  end

  private

  def send_report_to_qa_team
  end
end

如果您有简单的应用程序,那么回调是可以的,但是随着您的应用程序的增长,您会摸不着头脑,不确定是什么设置了这个或那个属性,并且测试会非常困难。

再想一想,我仍然认为您应该广泛使用回调并体验重构它的痛苦,然后您将学会避免它;)祝你好运

【讨论】:

  • 谢谢!以前从未见过服务对象。虽然我不确定这两个选项是否相同。前者如果 send_quality_report_to_qa_team 失败,对象创建会失败,而后者会成功。我相信所有活动的记录回调都是同一个事务的一部分,如果其中任何一个失败,数据库操作就会回滚
【解决方案2】:

before_create 回调可用于在对象保存到数据库之前设置对象的属性。例如,为记录生成唯一标识符。将其放入 after_create 将需要另一个数据库调用。

【讨论】:

    【解决方案3】:

    before_create:

    将在将新对象保存到数据库之前调用。当此方法返回 false 时,它​​将通过回滚来阻止创建。

    因此,当您需要在保存前检查某些内容时,不适合验证,您可以在 before_create 中使用它们。

    例如:在创建新的Worker 之前,请向Master 征求许可。

    before_create :notify_master
    
    def notify_master
      # notify_master via ipc and 
      # if response is true then return true and create this successfully
      # else return false and rollback
    end
    

    另一个用途是Trung Lê建议您在保存之前要格式化某些属性 比如大写名称等。

    after_create:

    第一次在数据库中保存对象后调用。只是当您不想中断创建并只是记下创建或在创建后触发某些内容时,这很有用。

    例如:创建新的user 角色mod 后,我们要通知其他模组

    after_create :notify_mod, :is_mod?

    def notify_mod
      # send notification to all other mods
    end
    

    编辑:以下评论

    问:将notify_mod 放入after_create 而不是before_create 有什么好处?

    答:有时在将对象保存到数据库时,由于数据库端验证或其他问题,它可能会回滚。

    现在如果你在创建之前写了notify_mod,那么即使创建没有完成,它也会被处理。毫无疑问,它会回滚,但会产生开销。所以很费时间

    如果你把它放在after_create 中,那么notify_mod 只会在记录创建成功时执行。从而减少发生回滚时的开销。

    另一个原因是,通知必须在创建用户之后而不是之前发送是合乎逻辑的。

    【讨论】:

    • 有意义(这也是我使用它的方式)。但是将 notify_mod 放入 after_create 而不是 before_create 有什么好处呢?我想这会让通话更干净......
    猜你喜欢
    • 2011-09-19
    • 2019-11-24
    • 1970-01-01
    • 2015-11-30
    • 2011-12-29
    • 2021-11-17
    • 2010-10-28
    • 2019-06-23
    • 1970-01-01
    相关资源
    最近更新 更多