1

Railsのメーラーからアクセスしようとしていますrequest.host(まあ、理想的には)。host_with_portrequest.host への実際の呼び出しは、ヘルパーにあります。

#/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]

config/environments/ で構成されたホストにアクセスするには、メーラーで、これが最も簡単な方法だと思います。

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

これは、それがであるとあなたに言っていrequestますnil。これは、コントローラーのスコープ外(つまり、拡張するクラス内ActionMailer::Base requestが存在しないためです。

のように他のデータを行うのと同じように、requestオブジェクトまたは必要な部分request.host_with_portだけをメーラーに渡す必要がありuserますemail_confirmation


したがって、次のようなcreateメソッドがあります

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メソッドを削除したり、ヘルパーからメソッドを削除したりできます。注意すべき2つのこと

  • 上記の私の例には、検証/エラーチェックの方法で何も含まれていません
  • 私の例では、どこtokenが定義され、使用されているかについて推測しています。

ご覧のとおり、この「worker」クラスを導入することで、重複することなく機能を明確に分離できます。

于 2013-01-12T02:40:35.720 に答える