active_delivery gemがいい感じ。
active_deliveryはActionMailer 的な処理 をまとめるWrapperです。
例によってWeb上にはREADMEと作者の方のブログエントリーしか見当たらなかったので、使い方を知るにはソース読んだ方が早いです。僕が代わりに読んでおいたのでちょっとしたプラス情報を書いておきます。
使い方
def after_signup
ActivityMailer.user_signup.deliver_later if user.receive_emails?
DiscordNotifier.user_signup.notify_later if user.receive_discord?
end
こんな感じに書いてたのを
def after_signup
ActivityDelivery.notify(:user_signup, user)
end
こんな感じに描けるようになります。
ActivityDelivery.notify!(:user_signup, user)
また、デフォルトでは非同期の方を呼び出しますが、notify!
の方だと同期版を呼んでくれます。
ActivityDelivery.with(user: user).notify(:user_signup)
そして、ActionMailerのようにParameterizedな呼び方もできます。
概要
直接使うDeliveryクラスと実際に動くMailerクラス(やその他の独自のDeliveryクラス)、その間をつなぐLineクラスがあります。
デフォルトで使われるActiveDelivery::Lines::Mailerを見るとどうやって間を繋いでいるのかがわかります。
実装
これを用意しておくだけで既に、
# app/deliveries/activity_delivery
class ActivityDelivery < ActiveDelivery::Base
end
下記が呼べてメールが送信されます。
ActivityDelivery.notify(:user_signup, user)
何故かとういうと、デフォルトでこういうクラスのメソッドを探してメソッドを呼んでくれるからです。
class_name.gsub(/Delivery$/, "Mailer")
Mailerはデフォルトで呼ぶんですね。
class ActivityDelivery < ActiveDelivery::Base
unregister_line :mailer
end
こうしておけばデフォルトのMailerを呼ぶのもなしにできます。
独自のDeliveryクラスを使うには自分でLineクラスを書く必要があります。
しかし、abstract_notifierを使って作った通知クラスがあれば、そちらにActiveDelivery::Lines::Notifer
クラスが同伴されているので自分で書く必要はないです。便利!
abstract_notifierについてはこちらのエントリーを見てください。
abstract_notifierで通知を実装する - komagataのブログ
class ActivityDelivery < ActiveDelivery::Base
register_line :discord,
ActiveDelivery::Lines::Notifier,
resolver: ->(_) { DiscordNotifier }
end
これでActivityMailerとDiscordNotifierのメソッドを一緒に呼んでくれるようになります。
テスト
テストはこんな感じで同期版・非同期版、普通版・Parameterized版をそれぞれテストしておけば安心だと思います。
require 'test_helper'
class ActivityDeliveryTest < ActiveSupport::TestCase
test '.notify(:user_signup)' do
params = {
body: 'user signup!'
user: users(:foo)
}
assert_difference -> { AbstractNotifier::Testing::Driver.deliveries.count }, 2 do
ActivityDelivery.notify!(:user_signup, **params)
end
assert_difference -> { AbstractNotifier::Testing::Driver.enqueued_deliveries.count }, 2 do
ActivityDelivery.notify(:user_signup, **params)
end
assert_difference -> { AbstractNotifier::Testing::Driver.deliveries.count }, 2 do
ActivityDelivery.with(**params).notify!(:user_signup)
end
assert_difference -> { AbstractNotifier::Testing::Driver.enqueued_deliveries.count }, 2 do
ActivityDelivery.with(**params).notify(:user_signup)
end
end
end