我正在尝试从Rails中的Mailer访问request.host
(好吧,理想情况下为host_with_port
)。对request.host的实际调用是在Helper中:
#/app/helpers/confirmations_helper
module ConfirmationsHelper
def email_confirm_url(token)
"http://#{request.host_with_port}/confirm/#{token}" # failure: undefined method
end
end
#/app/mailers/user_mailer
class UserMailer < ActionMailer::Base
default from: "email@domain.com"
add_template_helper(ConfirmationsHelper) #get access to helpers/confirmations_helper.rb
def email_confirmation(user)
@user = user
@url = "http://www.domain.com/"
mail(to: user.email, subject: "Email Confirmation")
end
end
#config/environments/development.rb
...
config.action_mailer.default_url_options = { :host => "localhost:3000" }
我得到的错误是:
ActionView::Template::Error:
undefined method `host' for nil:NilClass
答案 0 :(得分:9)
使用
ActionMailer::Base.default_url_options[:host]
在您的邮件程序中在config / environments /中访问配置的主机 我相信,这是最简单的方法。
答案 1 :(得分:4)
ActionView::Template::Error:
undefined method `host' for nil:NilClass
这告诉您request
是nil
。这是因为在控制器范围之外(即在扩展ActionMailer::Base
的类 request
中不存在。
您需要将request
对象或您需要的部分(request.host_with_port
)传递给邮件程序,就像您在其中执行其他数据user
一样email_confirmation
。
所以你有一个像这样的
的创建方法def create
@user = User.new
@user.assign_attributes(params[:user])
@user.save
@user.send_email_confirmation
end
在User
模型中,您有send_email_confirmation
这样的方法
class User < ActiveRecord::Base
def send_email_confirmation
UserMailer.email_confirmation(self).deliver
end
您的邮件程序email_confirmation
看起来像
def email_confirmation(user)
@user = user
@url = "http://www.domain.com/"
mail(to: user.email, subject: "Email Confirmation")
end
通过模型向邮件发送请求不是最好的主意;你应该保持清晰的关注点分离。这是您的问题的一部分,以及为什么在尝试将request
从控制器操作传递到邮件程序模板时发现不必要的复杂性。
我可能建议创建一个工人阶级。 Here 我解释了如何在lib/
中设置类 - 相同的概念可以应用于lib/your_app/workers/user.rb
之类的内容。
您可以在此课程中拥有以下内容
module YourApp
module Workers
module User
extend self
def create!(params, options{})
options.reverse_merge! host: ""
user = User.new
user.assign_attributes(params)
user.save
UserMailer.email_confirmation(user, host).deliver
user
end
end
end
end
您的控制器操作可能只是
def create
@user = ::YourApp::Worker::User.create!(params[:user], host: request.host_with_port)
end
您的邮件程序方法现在看起来像
def email_confirmation(user, host)
@user = user
token = "" # define token somehow
@url = "#{host}/confirm/#{token}"
mail(to: user.email, subject: "Email Confirmation")
end
最后,您可以从模型中删除send_email_confirmation
以及帮助程序中的email_confirm_url
方法,因为它们已不再使用。有两点需要注意
token
被定义和使用的位置正如您所看到的,通过引入这个“工人”类,可以实现功能的清晰分离而不会重复。