[英]Best way to save attribute inside save block?
In my controllers I often have functionality like this: 在我的控制器中,我经常具有以下功能:
@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
What's the best way to send an email and update the activation_sent_at
attribute without having to save the record twice? 发送电子邮件和更新activation_sent_at
属性而不必两次保存记录的最佳方法是什么? Calling update_column
doesn't feel right to me here because AFAIK it creates an extra SQL query (correct me if I'm wrong). 在这里调用update_column
感觉不对,因为AFAIK会创建一个额外的SQL查询(如果我输入错了,请更正我)。
Your code is fine. 您的代码很好。 I wouldn't change it. 我不会改变。
For example, you might be tempted to do something like this: 例如,您可能会想这样做:
@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
Aside from the small issue that there's now repeated logic around @account.guest?
除了小问题之外, @account.guest?
现在有重复的逻辑了@account.guest?
, what happens if AccountMailer.activation(@account).deliver_later
fails? , 如果AccountMailer.activation(@account).deliver_later
失败怎么办? (When I say "fails", I mean - for example - AccountMailer
has been renamed, so the controller returns a 500 error.) (当我说“失败”时,我的意思是-例如AccountMailer
已重命名,因此控制器返回500错误。)
In that case, you'd end up with a bunch of account
records which have an activation_sent_at
but were never sent an email; 在这种情况下,您最终将获得一堆具有activation_sent_at
但从未发送过电子邮件的account
记录; and you'd have no easy way to distinguish them. 并且您将没有容易的方法来区分它们。
Therefore, this code warrants running two database calls anyway: One to create the record, and then another to confirm that an email was sent. 因此,此代码保证无论如何都要运行两个数据库调用:一个创建记录,然后另一个确认发送了电子邮件。 If you refactor the code to only perform a single database call, then you'll become vulnerable to either: 如果将代码重构为仅执行单个数据库调用,那么您将很容易受到以下任一影响:
activation_sent_at
despite o email being sent. 尽管发送了电子邮件,但仍用activation_sent_at
标记用户。 The controller should be doing two transactions, not one. 控制器应该执行两次事务,而不是一次。 Which is why I said: Don't change it. 这就是为什么我说:不要更改它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.