はじめに
メールの送信機能を初めて実装したので、躓いたところや実装方法をメモとして残しておきます。
質問回答アプリで新規質問が投稿された際に、全員に対して質問があった旨をメールで通知する。
Action Mailer
Action Mailerを使うと、アプリケーションのメイラークラスやビューでメールを送信することができる。メイラーの動作はコントローラときわめて似通っている。メイラーはActionMailer::Baseを継承し、app/mailersに配置され、app/viewsにあるビューと結び付けられる。
Mailer作成手順
- メイラーを作成
rails g mailer QuestionMailer
class ApplicationMailer < ActionMailer::Base
default from: "from@example.com"
layout 'mailer'
end
開発環境でメール送信を確認する方法
mailcatcher
シンプルなsmtpサーバを立てて、送信されたメールをブラウザ上で確認できるようにしてくれる。
(cloud9でmailcatcherを実行しようとしたら、うまく実行出来ず原因はcloud9ではないかと考えられる。なので、メール確認のために代わりにletter_opener_webを使用しました。)
letter_opener_web
ローカル開発環境で送信したメールをブラウザ上で確認することができる
http://localhost:3000/letter_opener
にアクセスすることで送信されたメールを確認できる
cloud9で使う方法
- gemを追加
group :development do
gem 'letter_opener_web'
end
- ルーティング
mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?
- config デフォルトURLを指定(cloud9バージョン)
config.action_mailer.default_url_options = { host: 'myapp.c9users.io/', port: $PORT, protocol: 'https' }
config.action_mailer.delivery_method = :letter_opener_web
質問があった際に全員に対して質問があった旨をメールで通知する
class QuestionMailer < ApplicationMailer
default from: 'qanda@example.com'
def creation_email(user)
@user = user
mail(subject: '新規質問です',to: user.email, from: "qanda@example.com")
end
def self.creation_email_questions
@users = User.all
@users.each do |user|
QuestionMailer.creation_email(user).deliver_now
end
end
end
def create
@question = current_user.questions.new(question_params)
if @question.save
QuestionMailer.creation_email_questions
redirect_to questions_url, notice: "質問を「#{@question.title}」投稿しました。"
else
render :new
end
end
躓いたところ
これでも、全ユーザーにメールを送信することは可能だが、考え方が少し複雑な上にメイラーのビューで質問のタイトルや内容を表示するために@question使えない。あと、メーラにクラスメソッドを定義するやり方はあまりやらない。
改善するには
メーラのクラスメソッドで定義されている全ユーザーを取り出す処理をquestions_controllerで定義すれば、メーラにクラスメソッドを定義しなくても良くなる!
def create
@question = current_user.questions.new(question_params)
if @question.save
User.all.each do |user|
QuestionMailer.with(user: user, question: @question).creation_email.deliver_now
end
redirect_to questions_url, notice: "質問を「#{@question.title}」投稿しました。"
else
def creation_email
@user = params[:user]
@question = params[:question]
mail(subject: '新規質問',to: @user.email, from: "qanda@example.com")
end
このようにwith(question: @question)
と書くことでメイラーのアクションでparams[:question]
が使えるようになり、ビューでも@questionが使えるのでメールの内容を表示することができるようになる。あとはビューを編集して完成。