Hartl 教程第 13.1.3 章 User/Micropost 关联:为什么使用 create 而不是使用引发异常的 bang 创建?

Hartl Tutorial Chapter 13.1.3 User/Micropost associations: Why use create instead of create with a bang that raises exceptions?

Michael Hartl's rails tutorial chapter 13.3.1中,我们创建了一个twitter风格的微博,如下所示:

Micropost.create

我的问题是为什么使用 Micropost.create 而不是 Micropost.create!

似乎您总是希望在出现问题时在活动记录中引发异常,以便您可以解决异常。

为什么要使用 Micropost.create?他解释说,两者都是 table 的选项:

但他并没有真正解释为什么你会选择其中之一。那么,您为什么要选择一个而不是另一个?

如果 create 失败,您并非完全一无所知。

my_micropost = Micropost.create

if my_micropost.persisted?
  puts "successfully saved"
else
  puts "something went wrong"
end

它为您提供了一种处理失败情况的简单机制。例如,您可以参考 my_micropost.errors 以确定问题所在并进行相应处理。

而在不向最终用户公开异常的情况下从 create! 恢复意味着您需要从引发的异常中解救出来,这是一个更复杂的过程。

嗯,这取决于你在哪里使用这个方法。

何时使用create

如果是在你的controller中简单的创建,一般会使用create来控制流程逻辑,举个例子:

if Micropost.create(micropost_params)
  # handle success save, e.g.:
  redirect_to :index
else
  # handle failure in save, e.g.:
  render :new
end

使用上面的代码,您可以 控制流程 而无需 使用异常 ,这就是您创建记录时想要的:处理错误你知道这很可能会发生而不会引发异常。

所以,我更愿意反过来问:如果你可以得到 false 并处理错误,为什么要使用 create! 并引发异常(并获得相关的开销) ?如果我需要更多代码来处理该异常,为什么要这样做?

虽然这是一个有效的用法 create,但并不常见,因为 saveupdate 更有可能被使用(在大多数情况下,您将使用 new 然后保存 save).

何时使用create!

如果您想在同一操作中更新多条记录(阅读transactions),那么create! 会更好;考虑以下示例:

ActiveRecord::Base.transaction do
  user1.update!(balance: user1.balance + 100)
  user2.update!(balance: user2.balance - 100)
  transfer.create!(amount: 100, receiver: user1, sender: user2)
end

在这里,您在同一个事务中更新了 2 条记录并创建了 1 条记录,但是如果其中一条记录失败,您需要进行回滚以保持数据完整性。因此,如果您使用 create,您将需要自己处理回滚以撤消事务;另一方面,使用 create! 会引发异常,自动触发回滚。

create! 的另一个好用处是 testing(如 Hartl 的教程)和 debugging,我发现它们更方便因为它们有助于更快地发现错误。