代码之家  ›  专栏  ›  技术社区  ›  Tintin81

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

  •  0
  • Tintin81  · 技术社区  · 8 年前

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

    @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 在这里我觉得不对,因为它创建了一个额外的sql查询(如果我错了,请纠正我)。

    1 回复  |  直到 8 年前
        1
  •  2
  •   Tom Lord    8 年前

    你的密码没问题。我不会改变的。

    例如,您可能会尝试执行以下操作:

    @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 但从来没有人发过邮件,而且你很难区分他们。

    因此,这段代码保证运行两个数据库调用:一个创建记录,另一个确认发送了电子邮件。如果重构代码以仅执行一个数据库调用,则很容易受到以下任一情况的攻击:

    • 向未创建的用户发送电子邮件,或
    • 使用标记用户 激活发送时间 尽管有电子邮件发送。

    控制器 应该 做两个交易,而不是一个。所以我说:不要改变它。