首页 > 解决方案 > 在保存块内保存属性的最佳方法?

问题描述

在我的控制器中,我经常有这样的功能:

@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 查询(如果我错了,请纠正我)。

标签: ruby-on-railsrubyactiverecord

解决方案


你的代码很好。我不会改变它。

例如,您可能很想做这样的事情:

@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尽管发送了电子邮件,但仍用标记用户。

控制器应该做两个事务,而不是一个。这就是为什么我说:不要改变它。


推荐阅读