(NoMethodError: undefined method `email' for main:Object). Sending Welcome Email After Devise Confirm with Mandrill & Mailchimp
(NoMethodError: undefined method `email' for main:Object). Sending Welcome Email After Devise Confirm with Mandrill & Mailchimp
我目前正在覆盖 Devise Confirmable 方法以在用户确认其帐户后创建欢迎电子邮件。在当前设置下,运行 UserTransactionMailer.welcome_message(self).deliver_now 在 rails 控制台中导致以下错误:
"NoMethodError: undefined method `email' for main:Object
from /Users/AnthonyEmtman/Documents/projects/Team_Development/kons/app/mailers/user_transaction_mailer.rb:6:in `welcome_message'"
下面是 user.rb 中用于触发发送 welcome_message 电子邮件的 def confirm!
覆盖。
models/user.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable, :zxcvbnable
def confirm!
send_welcome_message
super
end
private
def send_welcome_message
UserTransactionMailer.welcome_message(self).deliver_now
end
end
以下文件是我的 user_transaction_mailer.rb 和 base_mandrill_mailer.rb 文件。 user_transaction_mailer.rb 继承自 base_mandrill_mailer.rb 因此我创建的所有未来邮件程序都可以访问 mandrill_send 方法,有效地减少了我每次需要编写的发送代码量到 mandrill_send方法。
mailers/user_transaction_mailer.rb:
class UserTransactionMailer < BaseMandrillMailer
def welcome_message(user, opts={})
options = {
:subject => "Welcome to Kontracking",
:email => user.email,
:global_merge_vars => [
{
name: "USER_NAME",
content: user.user_name
}
],
:template_name => "Welcome Message - Kontracking"
}
mandrill_send options
end
end
mailers/base_mandrill_mailer.rb:
require "mandrill"
class BaseMandrillMailer < ApplicationMailer
def mandrill_send(opts={})
message = {
:subject => "#{opts[:subject]}",
:from_name => "Kontracking",
:from_email => "admin@kontracking.com",
:to =>
[{"name" => "Some User",
"email" => "#{opts[:email]}",
"type" => "to"}],
:global_merge_vars => opts[:global_merge_vars]
}
sending = MANDRILL.messages.send_template opts[:template_name], [], message
rescue Mandrill::Error => e
Rails.logger.debug("#{e.class}: #{e.message}")
raise
end
end
运行 UserTransactionMailer.welcome_message(User.first).deliver_now 在 rails 控制台中导致成功发送到我的电子邮件,包括正确处理我包含了 merge_var of user_name 以显示在电子邮件中。我对哈希没有经验,目前无法找出未定义方法问题的解决方案(这可能相当简单)。我如何让它正常工作?
此外,我目前在初始化程序中需要 'mandrill',所以我应该能够将其从 base_mandrill_mailer.rb 文件中删除,对吗?
我解决了我的问题,因为当前的实现总是未定义 self。更改 models/user.rb 确认方法以将自己和用户包含在消息中解决了这个问题。
models/user.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable, :zxcvbnable
def confirm!
send_welcome_message(self)
super
end
private
def send_welcome_message(user)
UserTransactionMailer.welcome_message(user).deliver_now
end
end
所有其他文件都是正确的。我会向希望覆盖 Devise 邮件程序或特定方法并同时利用 Mailchimp/Mandrill 集成的任何人推荐这种方法——尤其是那些在开发团队中工作的人。此方法有效地允许您将电子邮件的设计和更新卸载到 non-technical 成员,并且不需要将电子邮件视图更改部署到服务器(变量名称或电子邮件添加的待定更改)。
我在下面包含了用于覆盖 Devise 的文件。
mailers/custom_devise_mailer.rb:
class CustomDeviseMailer < Devise::Mailer
def confirmation_instructions(record, token, opts={})
options = {
:subject => "Confirmation Instructions",
:email => record.email,
:global_merge_vars => [
{
name: "confirmation_link",
content: user_confirmation_url(confirmation_token: token)
}
],
:template_name => "Confirmation Instructions - Kontracking"
}
mandrill_send options
end
def reset_password_instructions(record, token, opts={})
options = {
:subject => "Password Reset Instructions",
:email => record.email,
:global_merge_vars => [
{
name: "password_reset_link",
content: reset_password_url(reset_password_token: record.reset_password_token)
}
],
:template_name => "Password Reset Instructions - Kontracking"
}
mandrill_send options
end
def unlock_instructions(record, token, opts={})
options = {
:subject => "Account Unlock Instructions",
:email => record.email,
:global_merge_vars => [
{
name: "account_unlock_link",
content: user_unlock_url(unlock_token: token)
}
],
:template_name => "Account Unlock Instructions - Kontracking"
}
mandrill_send options
end
def mandrill_send(opts={})
message = {
:subject => "#{opts[:subject]}",
:from_name => "Kontracking",
:from_email => "anthony.emtman@kredibleinc.com",
:to =>
[{"name" => "Some User",
"email" => "#{opts[:email]}",
"type" => "to"}],
:global_merge_vars => opts[:global_merge_vars]
}
sending = MANDRILL.messages.send_template opts[:template_name], [], message
rescue Mandrill::Error => e
Rails.logger.debug("#{e.class}: #{e.message}")
raise
end
end
您还需要更改 Devise 初始化程序中的邮件程序配置以指向您的自定义邮件程序。
initializers/devise.rb:
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config.mailer_sender = 'john.smith@example.com'
# Configure the class responsible to send e-mails.
config.mailer = 'CustomDeviseMailer'
我还为 Mandrill 设置了一个简单的初始值设定项(我使用的是 Mandrill API-- 下面包含的文件)。
initializers/mandrill.rb:
require 'mandrill'
MANDRILL = Mandrill::API.new ENV['SMTP_PASSWORD']
config/environments/production.rb:
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
config.action_mailer.default_url_options = { host: ENV["SMTP_DOMAIN"] }
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.smtp_settings = {
address: ENV.fetch("SMTP_ADDRESS"),
authentication: :plain
domain: ENV.fetch("SMTP_DOMAIN"),
enable_starttls_auto: true,
password: ENV.fetch("SMTP_PASSWORD"),
port: "587",
user_name: ENV.fetch("SMTP_USERNAME")
}
config/environments/development.rb:
# Care if the mailer can't send.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :test
host = 'localhost:3000'
config.action_mailer.default_url_options = { host: host }
config.action_mailer.perform_deliveries = true
config/application.yml:
SMTP_ADDRESS: smtp.mandrillapp.com
SMTP_DOMAIN: 本地主机
SMTP_PASSWORD: 'insert your Mandrill API key here--no quotes'
SMTP_USERNAME: 'insert your Mandrill Username here--no quotes'
我正在使用 figaro 来管理这些。我设置了一个初始值设定项,因此如果它们未在服务器上设置,则会导致错误。
initializers/figaro.rb:
Figaro.require_keys("SMTP_ADDRESS", "SMTP_DOMAIN",
"SMTP_PASSWORD", "SMTP_USERNAME")
如果您有任何问题,请告诉我!
我目前正在覆盖 Devise Confirmable 方法以在用户确认其帐户后创建欢迎电子邮件。在当前设置下,运行 UserTransactionMailer.welcome_message(self).deliver_now 在 rails 控制台中导致以下错误:
"NoMethodError: undefined method `email' for main:Object
from /Users/AnthonyEmtman/Documents/projects/Team_Development/kons/app/mailers/user_transaction_mailer.rb:6:in `welcome_message'"
下面是 user.rb 中用于触发发送 welcome_message 电子邮件的 def confirm!
覆盖。
models/user.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable, :zxcvbnable
def confirm!
send_welcome_message
super
end
private
def send_welcome_message
UserTransactionMailer.welcome_message(self).deliver_now
end
end
以下文件是我的 user_transaction_mailer.rb 和 base_mandrill_mailer.rb 文件。 user_transaction_mailer.rb 继承自 base_mandrill_mailer.rb 因此我创建的所有未来邮件程序都可以访问 mandrill_send 方法,有效地减少了我每次需要编写的发送代码量到 mandrill_send方法。
mailers/user_transaction_mailer.rb:
class UserTransactionMailer < BaseMandrillMailer
def welcome_message(user, opts={})
options = {
:subject => "Welcome to Kontracking",
:email => user.email,
:global_merge_vars => [
{
name: "USER_NAME",
content: user.user_name
}
],
:template_name => "Welcome Message - Kontracking"
}
mandrill_send options
end
end
mailers/base_mandrill_mailer.rb:
require "mandrill"
class BaseMandrillMailer < ApplicationMailer
def mandrill_send(opts={})
message = {
:subject => "#{opts[:subject]}",
:from_name => "Kontracking",
:from_email => "admin@kontracking.com",
:to =>
[{"name" => "Some User",
"email" => "#{opts[:email]}",
"type" => "to"}],
:global_merge_vars => opts[:global_merge_vars]
}
sending = MANDRILL.messages.send_template opts[:template_name], [], message
rescue Mandrill::Error => e
Rails.logger.debug("#{e.class}: #{e.message}")
raise
end
end
运行 UserTransactionMailer.welcome_message(User.first).deliver_now 在 rails 控制台中导致成功发送到我的电子邮件,包括正确处理我包含了 merge_var of user_name 以显示在电子邮件中。我对哈希没有经验,目前无法找出未定义方法问题的解决方案(这可能相当简单)。我如何让它正常工作?
此外,我目前在初始化程序中需要 'mandrill',所以我应该能够将其从 base_mandrill_mailer.rb 文件中删除,对吗?
我解决了我的问题,因为当前的实现总是未定义 self。更改 models/user.rb 确认方法以将自己和用户包含在消息中解决了这个问题。
models/user.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable, :zxcvbnable
def confirm!
send_welcome_message(self)
super
end
private
def send_welcome_message(user)
UserTransactionMailer.welcome_message(user).deliver_now
end
end
所有其他文件都是正确的。我会向希望覆盖 Devise 邮件程序或特定方法并同时利用 Mailchimp/Mandrill 集成的任何人推荐这种方法——尤其是那些在开发团队中工作的人。此方法有效地允许您将电子邮件的设计和更新卸载到 non-technical 成员,并且不需要将电子邮件视图更改部署到服务器(变量名称或电子邮件添加的待定更改)。
我在下面包含了用于覆盖 Devise 的文件。
mailers/custom_devise_mailer.rb:
class CustomDeviseMailer < Devise::Mailer
def confirmation_instructions(record, token, opts={})
options = {
:subject => "Confirmation Instructions",
:email => record.email,
:global_merge_vars => [
{
name: "confirmation_link",
content: user_confirmation_url(confirmation_token: token)
}
],
:template_name => "Confirmation Instructions - Kontracking"
}
mandrill_send options
end
def reset_password_instructions(record, token, opts={})
options = {
:subject => "Password Reset Instructions",
:email => record.email,
:global_merge_vars => [
{
name: "password_reset_link",
content: reset_password_url(reset_password_token: record.reset_password_token)
}
],
:template_name => "Password Reset Instructions - Kontracking"
}
mandrill_send options
end
def unlock_instructions(record, token, opts={})
options = {
:subject => "Account Unlock Instructions",
:email => record.email,
:global_merge_vars => [
{
name: "account_unlock_link",
content: user_unlock_url(unlock_token: token)
}
],
:template_name => "Account Unlock Instructions - Kontracking"
}
mandrill_send options
end
def mandrill_send(opts={})
message = {
:subject => "#{opts[:subject]}",
:from_name => "Kontracking",
:from_email => "anthony.emtman@kredibleinc.com",
:to =>
[{"name" => "Some User",
"email" => "#{opts[:email]}",
"type" => "to"}],
:global_merge_vars => opts[:global_merge_vars]
}
sending = MANDRILL.messages.send_template opts[:template_name], [], message
rescue Mandrill::Error => e
Rails.logger.debug("#{e.class}: #{e.message}")
raise
end
end
您还需要更改 Devise 初始化程序中的邮件程序配置以指向您的自定义邮件程序。
initializers/devise.rb:
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config.mailer_sender = 'john.smith@example.com'
# Configure the class responsible to send e-mails.
config.mailer = 'CustomDeviseMailer'
我还为 Mandrill 设置了一个简单的初始值设定项(我使用的是 Mandrill API-- 下面包含的文件)。
initializers/mandrill.rb:
require 'mandrill'
MANDRILL = Mandrill::API.new ENV['SMTP_PASSWORD']
config/environments/production.rb:
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
config.action_mailer.default_url_options = { host: ENV["SMTP_DOMAIN"] }
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.smtp_settings = {
address: ENV.fetch("SMTP_ADDRESS"),
authentication: :plain
domain: ENV.fetch("SMTP_DOMAIN"),
enable_starttls_auto: true,
password: ENV.fetch("SMTP_PASSWORD"),
port: "587",
user_name: ENV.fetch("SMTP_USERNAME")
}
config/environments/development.rb:
# Care if the mailer can't send.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :test
host = 'localhost:3000'
config.action_mailer.default_url_options = { host: host }
config.action_mailer.perform_deliveries = true
config/application.yml:
SMTP_ADDRESS: smtp.mandrillapp.com SMTP_DOMAIN: 本地主机 SMTP_PASSWORD: 'insert your Mandrill API key here--no quotes' SMTP_USERNAME: 'insert your Mandrill Username here--no quotes'
我正在使用 figaro 来管理这些。我设置了一个初始值设定项,因此如果它们未在服务器上设置,则会导致错误。
initializers/figaro.rb:
Figaro.require_keys("SMTP_ADDRESS", "SMTP_DOMAIN",
"SMTP_PASSWORD", "SMTP_USERNAME")
如果您有任何问题,请告诉我!