Подтвердить что ты не робот

Рекомендации ActionMailer: метод вызова в модели или контроллере?

Отправка электронной почты обычно вызывается после действия над моделью, но сама по себе электронная почта является операцией просмотра. Я ищу, как вы думаете о том, какие вопросы задают сами, чтобы определить, куда обращаться с вызовом метода почтовой программы.

Я видел/использовал их:

  • В модельном методе - плохое совмещение связанных, но разделенных проблем?
  • В обратном вызове модели (например, after_save) - лучшее разделение, насколько я могу сказать, с моим текущим уровнем знаний.
  • В действии контроллера - просто неправильно, но есть ли ситуации, если бы это был самый умный способ структурирования кода?

Если я хочу знать, как программировать, мне нужно думать, как программист, поэтому изучение того, как вы идете с мышлением через определенные программные решения, стоит месяцев в моей изоляции отдельно. Спасибо!

4b9b3361

Ответ 1

Поздний ответ, но я хочу рационализировать по этому вопросу:

Обычно в веб-приложении вы хотите отправлять электронные письма либо в качестве прямой реакции на клиента. Или в качестве фоновой задачи, если мы говорим о рассылке новостей/уведомлении о почте.

Модель в основном является устройством хранения данных. Его логика должна инкапсулировать обработку данных/связь с обработкой данных. Поэтому вставка логики, которая не связана с ней, немного сложна и в большинстве случаев ошибочна. Возьмем пример: Пользователь регистрирует учетную запись и получает электронное письмо с подтверждением. В этом случае можно сказать, что письмо с подтверждением является прямым следствием создания новой учетной записи. Теперь вместо того, чтобы делать это в веб-приложении, попробуйте создать пользователя в консоли. Звучит неправильно, чтобы вызвать обратный вызов в этом случае, правильно? Таким образом, функция обратного вызова поцарапалась. Должен ли мы писать метод в модели? Ну, если это прямой эффект действия пользователя/ввода, то он должен оставаться в этом рабочем процессе. Я бы написал его в контроллере после того, как пользователь был успешно создан. Непосредственно. Репликация этой логики в модели, которая будет вызываться в контроллере, в любом случае добавляет ненужную модульность и зависимость модели Active Record от Action Mailer. Попытайтесь рассмотреть возможность совместного использования модели во многих приложениях, в которых некоторые из них не хотят Action Mailer для нее. По указанным причинам я придерживаюсь мнения, что вызовы почтовой программы должны быть там, где они имеют смысл, и обычно модель не в этом месте. Попытайтесь дать мне примеры, где он это делает.

Ответ 2

Ну, зависит.

Я использовал все эти варианты и ваш вопрос о том, "зачем мне это делать?" это хорошо.

Если это то, что я хочу делать каждый раз, когда модель обновляется определенным образом, я помещаю ее в модель. Возможно, даже в обратном вызове в модели.

Иногда вы просто снимаете отчет; там ничего не обновляется. В этом случае у меня обычно есть ресурс с действием индекса, которое отправляет отчет.

Если почтовая программа не связана с измененной моделью, я мог бы увидеть ее обратный вызов. Я не очень часто это делаю. Я бы с большей вероятностью по-прежнему инкапсулировал его в модель. Я сделал это, только не очень часто.

Ответ 3

Я знаю, что прошло какое-то время, но лучшие практики никогда не умирают, верно?:)

Электронная почта по определению является асинхронной (за исключением электронной почты с подтверждением, но даже в этом случае лучше всего оставить задержку перед подтверждением).

Следовательно, на мой взгляд, наиболее логичным способом его отправки является:

  • в фоновом действии (используя Sidekiq или delayed_job)
  • в методе обратного вызова: "эй, это действие успешно выполнено, может быть, мы можем рассказать мир сейчас?"

Проблема в Rails заключается в том, что не слишком много обратных вызовов (например, в JS): Я лично считаю грязным, чтобы иметь код:

after_save :callback

def callback
  if test_that_is_true_once_in_the_objects_life
    Mailer.send_email()
  end
end

Итак, если вы действительно хотите думать, как программист, идея состоит в том, чтобы настроить вашу пользовательскую систему обратного вызова в вашем приложении.

Eg.

def run_with_callback(action, callback_name)
  if send(action)
    delay.send(callback_name)
  end
end

Или даже создание системы событий в вашем приложении было бы достойным решением.

Но, в конце концов, эти решения довольно дороги во времени, поэтому люди в конечном итоге записывают его в строку после действия

def activate
  [...]
  user.save
  Mailer.send_mail
  respond_to 
  [...]
end

который является самым близким способом для обратного вызова при синхронном программировании и результатов, имеющих вызов Mailers во всем мире (в Model и Controller).