Ruby on Rails:延迟的作业无法使用邮件程序并给出路由错误

Posted

技术标签:

【中文标题】Ruby on Rails:延迟的作业无法使用邮件程序并给出路由错误【英文标题】:Ruby on Rails: delayed jobs are not working with mailer and give route error 【发布时间】:2021-12-15 17:35:10 【问题描述】:

我尝试为我的邮件程序实现延迟作业,但即使按照文档进行操作也遇到了一些问题。

应用程序.rb

require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module AjaxApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.1
    config.action_view.embed_authenticity_token_in_remote_forms = true
    config.active_job.queue_adapter = :delayed_job
    
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
  end
end

我也有 config/initilizers/delayed_jobs.rb

Delayed::Worker.max_attempts = 5 #25
Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.sleep_delay = 60
Delayed::Worker.max_run_time = 5.minutes
Delayed::Worker.read_ahead = 10
Delayed::Worker.default_queue_name = 'default'
Delayed::Worker.delay_jobs = !Rails.env.test?
Delayed::Worker.raise_signal_exceptions = :term
Delayed::Worker.logger = Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))

还有迁移

class CreateDelayedJobs < ActiveRecord::Migration[6.0]
  def self.up
    create_table :delayed_jobs do |table|
      table.integer :priority, default: 0, null: false # Allows some jobs to jump to the front of the queue
      table.integer :attempts, default: 0, null: false # Provides for retries, but still fail eventually.
      table.text :handler,                 null: false # YAML-encoded string of the object that will do work
      table.text :last_error                           # reason for last failure (See Note below)
      table.datetime :run_at                           # When to run. Could be Time.zone.now for immediately, or sometime in the future.
      table.datetime :locked_at                        # Set when a client is working on this object
      table.datetime :failed_at                        # Set when all retries have failed (actually, by default, the record is deleted instead)
      table.string :locked_by                          # Who is working on this object (if locked)
      table.string :queue                              # The name of the queue this job is in
      table.timestamps null: true
    end

    add_index :delayed_jobs, [:priority, :run_at], name: "delayed_jobs_priority"
  end

  def self.down
    drop_table :delayed_jobs
  end
end

我也通过命令rails jobs:work 运行我的工人

完成所有这些设置后,我尝试发送密码重置电子邮件

我的密码_resets_controller.rb

 def create
    @user = User.find_by(email: params[:password_reset][:email].downcase)
    if @user
      @user.create_reset_digest
      @user.send_password_reset_email
      flash[:info] = 'Email sent with password reset instructions.'
      redirect_to root_url
    else
      flash.now[:danger] = 'Email address not found.'
      render 'new'
    end
  end

从user.rb中调用方法

def send_password_reset_email
    UserMailer.password_reset(self).deliver_later
#deliver_later must working under the hood of delayed_job
end 

我也试过

def send_password_reset_email
    UserMailer.delay.password_reset(self)
end

def send_password_reset_email
    UserMailer.password_reset(self)
end
handle_asynchronously :send_password_reset_email

在所有情况下,http://localhost:3000/delayed_job/failed?queues=mailers 都会出现错误(是的,我使用 gem 'delayed_job_web')

ID 1
Priority 0
Attempts 1
Queue mailers
Handler
--- !ruby/object:ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper
job_data:
  job_class: ActionMailer::DeliveryJob
  job_id: f5efa6e2-18e5-4d99-836b-8800d34b7289
  provider_job_id: 
  queue_name: mailers
  priority: 
  arguments:
  - UserMailer
  - password_reset
  - deliver_now
  - _aj_globalid: gid://ajax-app/User/1
  executions: 0
  exception_executions: 
  locale: en
  timezone: UTC
  enqueued_at: '2021-10-31T17:49:54Z'
Last Error No route matches :action=>"edit", :controller=>"password_resets", :email=>"psychotrop@gmail.com", :...

但我在 routes.rb 中有

resources :password_resets,     only: [:new, :create, :edit, :update]

当我使用没有延迟作业的邮件程序时,一切都按预期工作。 请帮助解决该问题。提前致谢!

更新

user_mailer.rb

class UserMailer < ActionMailer::Base
  default from: "psychotrop@gmail.com"

  #def welcome_email(user)
  #  @user = user
  #  @url  = 'http://example.com/login'
  #  mail(to: @user.email, subject: 'Welcome to Test Site')
  #end

  def registration_confirmation(user)
    @user = user
    mail(to: @user.email, subject: 'Verify your accounts')
    end
  #handle_asynchronously :registration_confirmation

    def account_activation(user)
    @user = user
    mail to: user.email, subject: "Account activation", template_name: 'account_activation'
  end
  #handle_asynchronously :account_activation

  def password_reset(user)
    @user = user
    mail to: user.email, subject: "Password reset", template_name: 'password_reset'
  end
  #handle_asynchronously :password_reset
  
end

password_reset.html.erb

<h1>Password reset</h1>

<p>To reset your password click the link below:</p>

<%= link_to "Reset password", edit_password_reset_url(@user.reset_token,
                                                      email: @user.email) %>

<p>This link will expire in two hours.</p>

<p>
If you did not request your password to be reset, please ignore this email and
your password will stay as it is.
</p>

更新 2

rake routes | grep password_reset

password_resets POST     /password_resets(.:format)                                                               password_resets#create
                   new_password_reset GET      /password_resets/new(.:format)                                                           password_resets#new
                  edit_password_reset GET      /password_resets/:id/edit(.:format)                                                      password_resets#edit
                       password_reset PATCH    /password_resets/:id(.:format)                                                           password_resets#update
                                      PUT      /password_resets/:id(.:format)                                                           password_resets#update

【问题讨论】:

似乎错误来自 UserMailer 的方法或电子邮件模板。您能否使用 UserMailer 代码和电子邮件模板编辑您的问题。 @NitinSrivastava。感谢您的回复。我添加了邮件和模板 似乎问题出在password_reset.html.erb 模板中的edit_password_reset_url(@user.reset_token, email: @user.email) url 中。要检查正确的 url,请在您的终端上运行 rake routes | grep password_reset 并使用命令结果更新问题。我们即将解决此问题。 @NitinSrivastava 谢谢你还在这里,我编辑了我的帖子。好像网址很好 【参考方案1】:

从路由中,edit_password_reset url 需要一个资源 ID。您可以通过将 @user 作为 url 的参数传递来修复它。

<%= link_to "Reset password", edit_password_reset_url(@user) %>

如果你想发送额外的参数然后

<%= link_to "Reset password", edit_password_reset_url(@user, reset_token: @user.reset_token, email: @user.email) %>

如果您想在 url 中使用 reset_password_token 而不是 :id,请使用自定义路由,例如

在 routes.rb 中

resources :password_resets, only: [:new, :create, :update] # Take out edit route

get '/password_resets/:reset_password_token/edit', to: "password_resets#edit", as: "edit_password_reset"

现在在电子邮件模板中

<%= link_to "Reset password", edit_password_reset_url(@user.reset_token) %>

如果您觉得这有帮助,请告诉我。

【讨论】:

以上是关于Ruby on Rails:延迟的作业无法使用邮件程序并给出路由错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ruby on Rails 中完成延迟作业后执行 ajax 回调?

禁用 ruby​​ on rails 作业进行测试

延迟作业无法在 Rails 应用程序中发送电子邮件。

Ruby on Rails 中的 Sendgrid / 电子邮件发送问题(托管在 Heroku 上)

Ruby on Rails Cron 作业示例

Rails/Rspec:测试延迟作业邮件