1

我正在尝试从 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
4

2 回答 2

10

采用

 ActionMailer::Base.default_url_options[:host]

在您的 Mailer 中访问 c​​onfig/environments/ 中配置的主机我相信,这是最简单的方法。

于 2013-08-14T23:23:35.490 回答
5
ActionView::Template::Error:
  undefined method `host' for nil:NilClass

这是在告诉你那requestnil。这是因为在您的控制器范围之外(即在类扩展中ActionMailer::Base request不存在。

您需要将request对象或您需要的部分( request.host_with_port)传递给邮件程序,就像您useremail_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控制器操作中的某些内容传递到邮件模板时发现不必要的复杂性的原因。

我可能建议的是创建一个工人阶级。在这里,我解释了如何在其中设置类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定义和使用的位置进行了假设

正如你所看到的,通过引入这个“工人”类,功能完全分离,没有重复。

于 2013-01-12T02:40:35.720 回答