Rails3:从Mailer中访问request.host

时间:2013-01-12 01:51:10

标签: ruby-on-rails ruby-on-rails-3 actionmailer helper

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

2 个答案:

答案 0 :(得分:9)

使用

 ActionMailer::Base.default_url_options[:host]
在您的邮件程序中

在config / environments /中访问配置的主机 我相信,这是最简单的方法。

答案 1 :(得分:4)

ActionView::Template::Error:
  undefined method `host' for nil:NilClass

这告诉您requestnil。这是因为在控制器范围之外(即在扩展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被定义和使用的位置

正如您所看到的,通过引入这个“工人”类,可以实现功能的清晰分离而不会重复。