Лучший способ сохранить атрибут внутри блока сохранения? - PullRequest
0 голосов
/ 01 июля 2018

В моих контроллерах у меня часто есть такие функции:

@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 голосов
/ 01 июля 2018

Ваш код в порядке. Я бы не стал его менять.

Например, у вас может возникнуть соблазн сделать что-то вроде этого:

@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 несмотря на то, что электронное письмо отправлено.

Контроллер должен выполнять две транзакции, а не одну. Вот почему я сказал: не меняй это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...