在保存块中保存属性的最佳方法?

时间:2018-07-01 10:32:35

标签: ruby-on-rails ruby activerecord

在我的控制器中,我经常具有以下功能:

@account = Account.new(account_params)
if @account.save
  if @account.guest?
    ...
  else
    AccountMailer.activation(@account).deliver_later
    @account.update_column(:activation_sent_at, Time.zone.now)
    flash[:success] = "We've sent you an email."
    redirect_to root_path
  end
end

发送电子邮件 并更新activation_sent_at属性而不必两次保存记录的最佳方法是什么?在这里打电话给update_column并不适合我,因为AFAIK会创建一个额外的SQL查询(如果我输入错了,请更正我)。

1 个答案:

答案 0 :(得分:2)

您的代码很好。我不会更改。

例如,您可能会想这样做:

@account = Account.new(account_params)
@account.activation_sent_at = Time.zone.now unless @account.guest?
if @account.save
  if @account.guest?
    ...
  else
    AccountMailer.activation(@account).deliver_later
    flash[:success] = "We've sent you an email."
    redirect_to root_path
  end
end

除了这个小问题,@account.guest?周围现在有重复的逻辑,如果AccountMailer.activation(@account).deliver_later失败了会发生什么?(当我说“失败”时,我的意思是-例如-AccountMailer已重命名,因此控制器返回500错误。)

在这种情况下,您最终会得到一堆account条记录,这些记录具有activation_sent_at但从未发送过电子邮件;并且您将没有容易的方法来区分它们。

因此,此代码保证无论如何都要运行两个数据库调用:一个创建记录,然后另一个确认发送了电子邮件。如果将代码重构为仅执行单个数据库调用,那么您将很容易受到以下任一影响:

  • 向未创建的用户发送电子邮件,或者
  • 尽管发送了电子邮件,但仍用activation_sent_at标记用户。

控制器应该进行两笔交易,而不是一笔。这就是为什么我说:不要更改它。