Рекомендации ActionMailer: метод вызова в модели или контроллере?
Отправка электронной почты обычно вызывается после действия над моделью, но сама по себе электронная почта является операцией просмотра. Я ищу, как вы думаете о том, какие вопросы задают сами, чтобы определить, куда обращаться с вызовом метода почтовой программы.
Я видел/использовал их:
- В модельном методе - плохое совмещение связанных, но разделенных проблем?
- В обратном вызове модели (например, after_save) - лучшее разделение, насколько я могу сказать, с моим текущим уровнем знаний.
- В действии контроллера - просто неправильно, но есть ли ситуации, если бы это был самый умный способ структурирования кода?
Если я хочу знать, как программировать, мне нужно думать, как программист, поэтому изучение того, как вы идете с мышлением через определенные программные решения, стоит месяцев в моей изоляции отдельно. Спасибо!
Ответы
Ответ 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
).