You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails Mailer报错:undefined method `[]' for nil:NilClass 求助

问题分析

报错undefined method []' for nil:NilClass的核心原因是**你同时在两个地方触发了邮件发送,其中模型的before_destroy回调没有传递agreement`参数**:

  • 控制器的destroy方法里,你用UserMailer.with(agreement: @agreement).agreement_delete.deliver_later正确传递了参数,这部分邮件能正常发送;
  • 但模型的before_destroy :check_delete回调里,直接调用UserMailer.agreement_delete.deliver,没有传递任何参数,导致邮件器里的params[:agreement]为nil,触发报错。

创建时邮件能正常工作,是因为创建场景下的邮件调用肯定传递了agreement参数(比如类似with(agreement: @agreement)的写法),和删除时的错误场景不匹配。

解决方案

步骤1:移除重复的模型回调

删掉agreement.rb里的before_destroy回调及对应方法,避免重复触发无参数的邮件调用:

# 移除以下代码
before_destroy :check_delete

private
def check_delete
      UserMailer.agreement_delete.deliver
end

步骤2:优化邮件器代码(可选,提升可读性)

Rails邮件器支持直接在方法中定义参数,比依赖params更直观:

def agreement_delete(agreement)
    @agreement = agreement
    @sent_user = User.find(@agreement.user_id)
    @user = User.find(@agreement.thought.user_id)
    @user_email = @user.email

    mail(to: @user_email, subject: "It's been deleted!")
end

对应的控制器调用修改为:

def destroy
    @agreement = Agreement.find(params[:id])
    UserMailer.agreement_delete(@agreement).deliver_later
    @agreement.destroy
    redirect_back 
end

步骤3:确认邮件触发时机(可选)

如果需要确保邮件在对象删除前发送完成(而非异步入队),可将deliver_later改为deliver_now,但异步发送更推荐,避免阻塞请求:

UserMailer.agreement_delete(@agreement).deliver_now

修改后即可解决参数nil的报错问题,同时保证邮件正常发送。

内容的提问来源于stack exchange,提问作者superbot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:27:15