Лучшие практики ActionMailer: метод вызова в модели или контроллере?

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

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

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

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


person inkdeep    schedule 03.02.2009    source источник


Ответы (4)


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

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

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

person ChuckE    schedule 24.09.2012
comment
Комментарий позже, но вот пример, который может иметь смысл в модели: когда электронное письмо инициируется после изменения статуса. Например, если пользователь заблокирован (например, изменить status на locked), он должен получить электронное письмо, независимо от того, как он был заблокирован. Что вы думаете? - person Gerry; 17.08.2017

Ну, зависит.

Я использовал все эти варианты и ваш вопрос о том, «почему я должен размещать это где?» хорошо.

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

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

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

person wesgarrison    schedule 03.02.2009

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

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

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

  • в фоновом режиме (используя 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).

person Augustin Riedinger    schedule 16.10.2014

Есть несколько причин, по которым контроллеры являются хорошим местом для почтовых программ:

  • Электронные письма, которые не имеют ничего общего с моделью.
  • Если ваши электронные письма зависят от нескольких моделей, которые не знают друг о друге.
  • Извлечение моделей в API не должно означать повторной реализации почтовых программ.
  • Содержимое Mailer определяется переменными запроса, которые вы не хотите передавать в модель.
  • Если ваша бизнес-модель требует большого количества разных электронных писем, обратные вызовы модели могут складываться.
  • Если электронная почта не зависит от результата расчетов модели.
person aelosada    schedule 20.02.2018