刚刚学 ROR,跟着《Ruby on Rails Tutorial》做的例子,部署的时候使用了 mailer 发送邮件; 无意间翻到文档中说相比使用 deliver_now 即时发送,使用 deliver_later 异步发送比较好。 这个时候报了一个错误给我,说是生成邮件模板中的一个具名路由方法缺少 ID,这个 ID 是我在 User 类中定义的属性 activation_token, 使用 deliver_now 时没有问题,但是在使用 deliver_later 的时候这个值丢失了;在邮件模板中将变量改成一个常量,异步发送邮件成功(邮箱有收到)。 也就是说问题就在参数值丢失这里。ruby 没学好理不知道原理,发上来请大家帮忙看一下。下面贴上关键代码
首先是 controllers/users_controller.rb 通过 create 开始整个流程
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
# 处理注册成功的情况
@user.send_activation_email # 发送激活邮件
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
end
然后是 models/user.rb,里面有发送激活账号的邮件方法,用 debugger 在这里调试 self.activation_token 还有值
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token, :reset_token
before_create :create_activation_digest
#返回指定字符串的哈希摘要
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# 返回一个随机令牌
def User.new_token
SecureRandom.urlsafe_base64
end
# 发送激活账号的邮件
def send_activation_email
# debugger
UserMailer.account_activation(self).deliver_later
end
# 设置密码重设相关的属性
def create_reset_digest
self.reset_token = User.new_token
update_columns(reset_digest: User.digest(reset_token),
reset_sent_at: Time.zone.now)
# update_attribute(:reset_digest, User.digest(reset_token))
# update_attribute(:reset_sent_at, Time.zone.now)
end
# 发送密码重设的邮件
def send_password_reset_email
UserMailer.password_reset(self).deliver_now
end
private
# def update_columns(params={})
# params.each do |key, value|
# self.update_attribute(key, value)
# end
# end
def downcate_email
self.email = email.downcase
end
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
mailers/user_mailer.rb,这里执行 mail 方法绑定邮件模板生成邮件,就是这儿 user.activation_token 值变成了 nil
class UserMailer < ApplicationMailer
default from: "[email protected]"
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.account_activation.subject
#
def account_activation(user)
@user = user
#@greeting = "Hi"
mail to: user.email, subject: "account activation"
end
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.password_reset.subject
#
def password_reset(user)
@user = user
#@greeting = "Hi"
mail to: user.email, subject: "Password reset"
end
end
生成邮件模板的 html 文件 /views/user_mailer/account_activation.html.erb,text 版大同小异就不发了
<h1>Sample App</h1>
<p>Hi <%= @user.name %>,</p>
<p>
Welcome to the Sample App! Click on the link below to activate your account:
</p>
<%= link_to "Activate", edit_account_activation_url(@user.activation_token,
email: @user.email) %>
本身.net 转过来的,我觉着这地方就是学得太浅没理解到位的问题。。请各位朋友指点一下,非常感谢。
补上错误日志,我自己描述可能还是不太准确。。出错的地方就是在 /views/user_mailer/account_activation.html.erb 里面。
调试的图片,使用 deliver_later 发送邮件时的调试
调试的图片,使用 deliver_now 发送邮件时的调试
最后问一个无关的,为什么我在使用 mailer 的时候,user_mailer.rb 中 default from: "[email protected]" 这一行注释掉,然后在 config/environments/development.rb(production.rb) 中使用 config.action_mailer.default_options = {from: '[email protected]'} 不起作用,仍然会因为发送邮箱和发送人不一致的问题导致 smtp 登录失败,现在我都是这样写 default from: "[email protected]" 才能登陆成功。