Railsのアソシエーションのタイポを検出する

2024/09/20に公開

歴史あるRailsアプリではアソシエーションにタイポがある

何年も経過したRailsのアプリケーションをメンテナンスをしていると、自分が知らないクラスはたくさんあります。
そしてクラス同士の関連を示すアソシエーションは、クラス自体よりも多くあったりもします。
その中で意外と見つけにくいのが、アソシエーションのタイポです。
なぜなら、全く使っていないならば動かないのでエラーも発生しないためです。
これはActiveRecordがRubyの動的な仕組みを活かして実装されていることが原因です。

最初にModelを定義したときに、とりあえず設定しておいたアソシエーションが、使われないままサービスが動いていることはよくあることですね。
しかし、問題は発生していなくとも、いざ機能を修正する際に触ることもあるでしょう。
その前に検知できていれば、驚くことも減るのではないでしょうか?
そんなときに使えるスクリプトを作ったので共有します。

検出スクリプト

require 'rails'

# Railsアプリケーションをロードする
require File.expand_path('config/environment', __dir__)

# すべてのモデルをロードする
Rails.application.eager_load!

# モデル情報を取得する
ActiveRecord::Base.descendants.each do |model|
  next if model == ActiveRecord::SchemaMigration # SchemaMigrationモデルはスキップ

  model.reflect_on_all_associations.each do |association|
    begin
      association_name = association.name
      # タイポしていると該当するclass名が無くて例外発生
      association.class_name
    rescue NoMethodError => e
      puts "Model: #{model.name}"
      puts "  Association Name: #{association_name}"
      puts
    end
  end
end

実行は以下のように runner で行います。

rails runner association_checker.rb

結果は以下のように出てきます。
このModelのアソシエーション部分を見てみると、何かしらのタイポや設定ミスが見つかるはずです。
手元のリポジトリではuserusrとなってしまっていた箇所などを検知できました。

Model: Hoge
  Association Name: hogehoge

Model: Fuga
  Association Name: fugafuga

スクリプトはgistにも上げています。

https://gist.github.com/iwtn/445b12ba9b03672a52fe0eaf5e199c8d

Livesense Engineers

Discussion