🐙
【Rails】Model.find失敗時にNotFoundErrorが発生する内部的な仕組み
一度はActiveRecode moduleの中に潜ったことありますよね。
自分は始めたての頃に「このメソッドが失敗したら、このエラークラスが実行される」っていう仕組みが何が何だかわからなかったので、ActiveRecodeの内部実装を見ながらfindメソッドの一例を解説します。
ActiveRecode module
よく使うwhere,find,create
とかのActiveRecodeから提供されるメソッドは、railsの/rails/activerecode/lib/active_recode/
配下のファイルにそれぞれ実装されています。
- where
/rails/activerecode/lib/active_recode/relation/query_methods.rb
def where(*args)
if args.empty?
WhereChain.new(spawn)
elsif args.length == 1 && args.first.blank?
self
else
spawn.where!(*args)
end
end
- create
/rails/activerecode/lib/active_recode/persistence.rb
def create!(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
else
object = new(attributes, &block)
object.save!
object
end
end
その中で、今回はfindメソッドについて詳細に見ていきます。
FinderMethods module
見ていただけるとわかりますが、finderの名前の通り「絞り込んで取得する系」のメソッドがまとまっています.
find
/rails/activerecode/lib/active_recode/relation/finder_methods.rb
def find(*args)
return super if block_given?
find_with_ids(*args)
end
def find_with_ids(*ids)
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
expects_array = if klass.composite_primary_key?
ids.first.first.is_a?(Array)
else
ids.first.is_a?(Array)
end
return [] if expects_array && ids.first.empty?
ids = ids.first if expects_array
ids = ids.compact.uniq
model_name = @klass.name
case ids.size
when 0
error_message = "Couldn't find #{model_name} without an ID"
raise RecordNotFound.new(error_message, model_name, primary_key)
when 1
result = find_one(ids.first)
expects_array ? [ result ] : result
else
find_some(ids)
end
end
- findメソッドにブロックが渡された場合(
block_given?
)、早期returnを抜けてfind_with_ids
を実行する -
find_with_ids
内で色々やってids
にidの配列が格納された状態でcase文でsize(配列の要素数)による分岐処理を行う - 見つけました。今回の主題である
raise RecordNotFound.new
の実行箇所です。ids
の要素数が0だった場合にraise
でエラークラスが実行されています。このerror_messageをいつもブラウザやpostmanで見ていたわけですね。
ActiveRecodeのメソッド実行に失敗した時に特定のエラークラスが実行される仕組みをざっくり理解できました。
ここまで読んでいただき、ありがとうございました。
Discussion