なぜ今回の記事を書いたか。
Railsの場合、ポリモーフィック関連付けを行なった際に紐づくモデルに対して実装しなければいけないメソッドの強制が行われません。そのため、メソッドの定義を忘れた場合エラーが発生します。
ただ、実装する際に忘れるメソッドのテストを書くのは難しいのでは? と個人的に思いました。
そのため、良し悪しは別として僕が実装したテストを記載します。
他に良い方法があれば是非教えてください!
実装したモデル
今回の記述に関係ない箇所に関しては省略しています。
app/models/notification.rb
class Notification < ApplicationRecord
belongs_to :event, polymorphic: true
・
・
・
end
app/models/comment.rb
class Comment < ApplicationRecord
has_many :notifications, as: :event, dependent: :destroy
・
・
・
def notification_message()
"#{self.user.name}によりコメントされました。"
end
end
実装したテスト
ポリモーフィック関連付けに紐づくテストなので、Notificationのモデルテストに記載いたしました。
spec/models/notification_spec.rb
require 'rails_helper'
RSpec.describe Notification, type: :model do
it 'Notificationと関連づいているクラスに対して必要なメソッドが定義されているか' do
# 定数オブジェクトの一覧を取得。
constants = Object.constants.map do |name|
Object.const_get(name)
end
# Notificationモデルと紐づいているモデルを取得する
models = constants.select do |c|
# モデルクラスを絞り込む
next unless c.class == Class && c < ActiveRecord::Base && !c.abstract_class?
# Notificationモデルが紐づいているか絞り込む
c.reflect_on_all_associations.map(&:name).include?(:notifications)
end
models.each do |model|
# 定義されたメソッドがあるかを確認する
expect(model.method_defined?(:notification_message)).to be true
end
end
end
この実装を行う事で、自動的にポリモーフィック関連付けされたモデルに必要なメソッドが存在しているかを確認してくれる。これでポリモーフィック関連付けを行なった際にメソッド忘れは無くなります!
懸念点
- モデルの数が多くなった時にテスト時間が増えそう
- モデルテストで、他のモデルにメソッドがあるか確認するのは良いのか?
- テストでここまで処理を書くのは良いのか?
- ポリモーフィック関連付けで関連づいたモデルに対してメソッドの強制を行う方法が他にあるのではないか?
- 継承やmoduleを使用した方が良いのではないか?