2

Я использую Delayed Job как мой ActiveJob очередей бэкэнда, и я пытаюсь отправить электронную почту с помощью ActionMailer «s deliver_later метода. Я считаю, что у меня все настройки Delayed Job правильные, и я запускаю фона рабочего на моей машине разработки.ActionMailer не может найти reset_token, отчеты отсутствует: идентификатор ключа

Когда я посылаю письмо для сброса пароля, я получаю следующее сообщение об ошибке:

[Worker(host:Computer pid:7240)] Job ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper (id=1) FAILED (5 prior attempts) with ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"password_resets", :email=>"[email protected]", :id=> nil} missing required keys: [:id]

Вот как я отправка электронной почты для сброса пароля. Это находится в моей User модели:

def send_password_reset_email 
    UserMailer.password_reset(self).deliver_later 
end 

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

Любая помощь была бы принята с благодарностью!

ответ

0

Я понял! У меня был ответ все время; Мне нужно было сохранить reset_token в базе данных. Я скопирую ответ от this Stack Overflow post ниже. Кредит отправляется в sevenseacat для ответа.

When you don't use workers, you're storing the reset_token in the User instance, then passing that same User instance to your mailer - hence the reset_token is still available.

When you use workers, your worker only has the User's ID, so it's reloading the User instance from the database. Because the reset_token isn't being stored in the database, it's coming back nil.

Either you should be saving the reset_token in the database, or your password email should be using reset_digest in the URL

После того как я изменил мою reset_token от виртуального атрибута столбца базы данных, проблема была решена. Теперь меня отправляют электронные письма с паролем.

EDIT (18 января 2016)

Я хотел бы добавить немного дополнительной информации, объясняющую, почему reset_token решить проблему, даже если сообщение об ошибке утверждал, что id отсутствовал. В моем Восстановление пароля по электронной почте, я генерировать edit пароль сброса URL действия следующим образом:

<%= edit_password_resets_path(@user.reset_token) %> 

Маршрут для моего редактирования действия сброса пароля выглядит следующим образом:

edit_password_resets GET /password_resets/:id/edit 

При создании URL, то первый параметр, который вы указываете, заполняет сегмент URL-адреса :id. В моем случае @user.reset_token заполнялся для id, в результате чего сгенерированный URL-адрес был /password_resets/{reset token here}/edit. Когда асинхронное задание пыталось сгенерировать URL-адрес, оно ожидало, что значение будет указано для сегмента id URL-адреса. Я положил свой reset_token на id, а так как reset_token был виртуальным атрибутом и был равен nil, когда ActiveJob побежал, он выбросил ошибку, так как не хватало значения.

0

Я просто пытался решить подобную проблему сам и пришел к немного другому решению. Чтобы избежать сохранения маркера сброса в базе данных, вы можете реорганизовать свой UserMailer.password_reset(self), чтобы принять два параметра UserMailer.password_reset(self, self.reset_token).Затем создайте две переменный экземпляр, чтобы передать в шаблон почтовой программы:

@user = user 
@reset_token = reset_token 

и, наконец, в самом шаблоне почтовой программы, вы можете просто сделать:

<%= edit_password_resets_path(@reset_token) %>` 
+0

Спасибо за разделение вашего решения. Вскоре после того, как я написал свое решение, я пошел по маршруту, подобному этому. Я создал отдельное задание и передал токен сброса пароля в полезную нагрузку задания следующим образом: этот код вызывается в модели «Пользователь». 'SendPasswordResetJob.perform_later (self.id, self.password_reset_token)' – Alexander