RecordNotFound で 404 Not found
Scaffold されたコード
Rails で scaffold したばかりのソースコードでは、あるモデルを表示するためのアクション (show) は以下のように記述されている。
# GET /series/1
# GET /series/1.xml
def show
@series = Series.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @series }
end
end
この場合、params[:id] が存在しない値だった場合、ActiveRecord::RecordNotFound が発生する。
development 環境だった場合、以下のような stacktrace が表示されるだろう。
これが production 環境だった場合、 Module: ActionController::Rescue#rescue_action で補足されて404 Not Found が表示される。
ソースコード改悪後
アプリケーションを開発していくと scaffold されたソースコードがそのまま残ることは多くない。 例えば指定されたモデルがあるユーザに確実に所有してされていることを保証したいと考えて、 以下のようにコードを改変したとする。
# GET /series/1
# GET /series/1.xml
def show
- @series = Series.find(params[:id])
+ @series = Series.find_by_id_and_user_id(params[:id], current_user.id)
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @series }
end
end
この場合、該当するモデルが存在しなかった場合でも ActiveRecord::RecordNotFound は発生せず、 @series は nil になる。
相当運が良くない限り、このソースコードを production 環境で運用すれば、 該当するモデルが存在しなかった場合、404 Not Found ではなく、5xx Application Error と表示されてしまう。
ソースコードの修正
これはあまり格好のいい話ではないので、 このような場合は nil をチェックして自分で ActiveRecord::RecordNotFound を発生させるべきだと思う。
# GET /series/1
# GET /series/1.xml
def show
- @series = Series.find(params[:id])
+ @series = Series.find_by_id_and_user_id(params[:id], current_user.id)
+ raise ActiveRecord::RecordNotFound if @series.nil?
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @series }
end
end