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」クラスを導入することで、重複することなく機能を明確に分離できます。