どうもこんばんは、先週に引き続き久保田です。
次はAction Cableだ!と思っていたのですが、既にやり方は僕より1_000_000倍くらい優秀なRubyistの方々が取り上げていましたので、僕の出番でないなと思いました。
じゃあ何を書こうか、と悩んでいたところ、あることに気づきました。
僕は記事を書けるほどRailsのことを知っているのか、と。
ちゃんと勉強せず使っていました。
どこかで「Railsなんて」と軽視している自分がいたのかもしれません。
こんなことではだめだ。真のRubyistへの道は遠い。
と、感じ、今回からRailsを頭の先から足の先、まで調べ上げて丸裸にしてやろうと思う所存でございます。
今回は、「Action Mailer」です。
今まで聞いたことだけあって、実際意識して使ったことがないので、今回メールを送ってみたいと思います。
まず、generateします。
bundle exec rails g mailer Greet
色々できましたね。
create app/mailers/greet_mailer.rbinvoke erbcreate app/views/greet_mailerinvoke test_unitcreate test/mailers/greet_mailer_test.rbcreate test/mailers/previews/greet_mailer_preview.rb
Rails Guides によると、mailerはcontrollerみたいなものと書いてあります。
確かにviewがありますね。これを使ってテンプレートを作るみたいです。
さて、早速実装します。
まずは、設定です。メールサーバーなどの設定をしていきます。
今回は、AWSのSESを使用しました。
環境は適宜読み替えてください。
# config/environments/development.rbconfig.action_mailer.raise_delivery_errors = true # テスト用にerrorを出すconfig.action_mailer.smtp_settings = {address: '選んだリージョンごとのアドレス',port: 587,domain: 'gmail.com',user_name: ‘SESでsmtpを設定したときに与えられるユーザー名です’,password: ‘SESでsmtpを設定したときに与えられるパスワードです’,}
そして
app/mailers/greet_mailer.rb です。
コントローラーみたいなやつですね。
コントローラーみたいなやつですね。
ここにメールを送る処理を書きます。
class GreetMailer < ApplicationMailerdefault form: 'test@gmail.com'def greetmail(to: 'test@gmail.com', subject: 'hello') do |f|f.text {render text: 'hello world'}endendend
この状態で、rails console からメソッドを呼び出してみましょう。
[1] irb > GreetMailer.greet.deliver
これでできちゃうんですね。
簡単。これは素晴らしいですね!
しかしあまりにも味気ないので、viewを触り、そして添付ファイルをつけてみましょう。
まずはviewを触ってみます。
今回はerbファイルをテンプレートととして使います。htmlでもテキストファイルでも結構です。
htmlならば、タグが使えます。
# app/views/greet_mailer/greet.html.erb<h1><%=@greet%></h1>
# app/views/greet_mailer/greet.text.erb
テキストならば、インスタンス変数のみを書いておきます。
@greet
ではcontrollerから、どのファイルを読むか指定します。
# app/mailers/greet_mailer.rbclass GreetMailer < ApplicationMailerdefault form: 'test@gmail.com'def greet@greet = “hey!” # ここでインスタンス変数を作成mail(to: 'test@gmail.com', subject: 'hello') do |f|f.html # htmlを使うときはこちらf.text # textを使うときはこちらendendend
こちらも非常に簡単ですね。モデルアクセスのロジックを組めばもっと使い勝手が良くなりそうですね。
では次は添付画像をつけてみます。
使うのはattachmentsというメソッドです。
# app/mailers/greet_mailer.rbclass GreetMailer < ApplicationMailerdefault form: 'test@gmail.com'def greet@greet = “hey!” # ここでインスタンス変数を作成mail(to: 'test@gmail.com', subject: 'hello') do |f|f.html # htmlを使うときはこちらf.text # textを使うときはこちらendendend
こちらも簡単!この簡単さが愛される理由かもしれませんね。
一旦ここまでで終了です。
すごく簡単に、直感的にしかも管理がしやすくメールが送れるので、かなりいいGemだと思います!
すごく簡単に、直感的にしかも管理がしやすくメールが送れるので、かなりいいGemだと思います!
さてここからは、少しGemの中を覗いてみましょう。
まずGemの場所を聞いてみます。
bundle show gem名
でGemの場所が分かります。
ちなみに
bundle open gem名
で該当のGemをeditorで開けます。
今回はメールを送る際のdeliverメソッドの挙動、色々なメール方式の取り扱い方を調べてみたいです。
まず、適当にそれっぽいのを探します。
ag delivery
すると
lib/action_mailer/delivery_methods.rb
に多数のdeliveryが見つかりますね。見てみましょう。
このmoduleはどうやら、色々なメールの方式が定義されているみたいですね。
初期設定を色々やってますね。
class_attributeやcater_accessorで変数やアクセサを定義し、
他のクラスからincludeされた時に設定をそのクラスからも呼べるようにしていますね。
おそらくここの設定を他のクラスがincludeして使う感じになるのでしょう。いいですね。
そして、おそらく重要なのは、「add_deliver_method」でしょう。このメソッドが各メール方式をうまく閉じ込めていそうです。
# lib/action_mailer/delivery_methods.rbdef add_delivery_method(symbol, klass, default_options={})class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings")send(:"#{symbol}_settings=", default_options)end
ClassMethodsモジュールに入っているので、DeliveryMehtodsのクラス変数になっていますね。
そして呼び出し側を見てみると、カッコがないのでわかりにいくですが、
第一引数で方式を、第二引数でクラスを渡すことで、メール方式名のclass_attributesを定義すると同時に、
delivery_methodsというクラス変数にペアにして登録しています。
そして、第三引数でハッシュを渡すことでメール方式名のclass変数に初期設定がなされていますね。
address: "localhost",port: 25,domain: 'localhost.localdomain',user_name: nil,password: nil,authentication: nil,enable_starttls_auto: true
おそらくdeliverメソッドは、このmoduleで定義される数々の設定から、configで設定されたメール方式の設定を受け取り、どれを使うかを選び、メールを送っているのでしょう。
このmoduleを拡張すれば、独自のメール方式も定義できそうですね。
さてでは実際メールを送っている処理が見てみたいものです。
引き続きdeliverを探してみると、
def deliverというものはどうやらないらしいです。しかし近いものは見つけました。
MessageDeliveryクラス(lib/action_mailer/message_delivery.rb)です。
この中を見てみると、
deliver_now, deliver_later
というメソッドがありました。
def deliver_nowmessage.deliverend
もしやと思い、このmessageを見てみると、
書いてありますね。
# Returns the Mail::Message objectdef message__getobj__end
で、少し長くなってきたので割愛しますが、ここからすすんでいくと最終的にActionMailer::Baseクラスで、Mailオブジェクトをリターンしていました。
このMessageDeliveryクラス自体はActionMailer::Baseのmethod_missingでインスタンスが作られており、さらにその中でmessageとしてMailオブジェクトが作られ、最終的にMailオブジェクトに対して、deliverが呼ばれていました。
このMessageDeliveryクラス自体はActionMailer::Baseのmethod_missingでインスタンスが作られており、さらにその中でmessageとしてMailオブジェクトが作られ、最終的にMailオブジェクトに対して、deliverが呼ばれていました。
MessageDeliveryクラスの上の方にもコメントでこのクラスはMail::Messageのラッパーだよって言ってますね。
これ以上はMailとの連携の部分なので、今度Mailを読んだ時にまた見てみようと思います。
今回は以上です。
次はまた違うGemを見てみたいと思います!