はじめに: バリデーションエラー時に警告が出る!?
Railsで以下のようなコントローラがあったとします。
class BlogsController < ApplicationController
# ...
def create
@blog = Blog.new(blog_params)
respond_to do |format|
if @blog.save
format.html { redirect_to @blog, notice: "Blog was successfully created." }
format.json { render :show, status: :created, location: @blog }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @blog.errors, status: :unprocessable_entity }
end
end
end
# ...
バリデーションエラーが起きたときは以下のコードが実行されます。
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @blog.errors, status: :unprocessable_entity }
が、rack 3.1.0 rack 3.2.0以降を使っている場合、このコードが実行されたタイミングで以下のような警告が出力されます1。
warning: Status code :unprocessable_entity is deprecated and will be removed in a future version of Rack. Please use :unprocessable_content instead.
(ChatGPT翻訳)
警告: ステータスコード :unprocessable_entity は非推奨であり、Rack の将来のバージョンで削除されます。代わりに :unprocessable_content を使用してください。
この記事ではこの問題の対応方法を説明します。
対応方法その1: unprocessable_contentに書き替える
ひとつは警告の内容に従って、コード内の:unprocessable_entity
をすべて:unprocessable_content
に書き替えることです。
-format.html { render :new, status: :unprocessable_entity }
+format.html { render :new, status: :unprocessable_content }
こうすると、警告が表示されなくなります。
ただし、gemの内部で:unprocessable_entity
が使われていたりすると、コードの置換ができないので警告が出続けます。
対応方法その2: Rails 8.0.3以上にアップデートする(おすすめ🌟)
もう一つの方法は、Rails 8.0.3以上にアップデートすることです。
-gem "rails", "8.0.2.1"
+gem "rails", "8.0.3"
bundle update rails
2025年9月22日にリリースされたRails 8.0.3では、以下のプルリクエストがマージされています。
このプルリクエストでは、rack 3.1.0以上を利用している場合に、自動的に:unprocessable_entity
を:unprocessable_content
に切り替えてくれます。
そのため、既存のコードを書き替えずとも、rackの警告は表示されなくなります。
また、gemの内部で:unprocessable_entity
が使われていたりした場合でも、Railsがうまく処理してくれるはずです。
参考情報1: Rails 7.2でもそのうち対応されるはず
この修正はRails 7.2のブランチにも適用されています。
ただし本記事の執筆時点(2025年9月24日)では、まだ公式リリースされていません。
おそらくこの修正は次のバージョン(7.2.3?)でリリースされると思います。
ただし、Rails 7.2ではこの警告に遭遇するケースはまれだと思われます。
その理由についてはコメント欄を参照してください。
参考情報2: scaffoldで生成されるコードはどうなる?
上で紹介した修正PRでは、scaffoldで使われるテンプレートも:unprocessable_entity
と:unprocessable_content
を適切に使い分けるように修正されています。
試しにscaffoldを実行してみましょう。
rails g scaffold Post content:text
生成されたコードを見てみると・・・
class PostsController < ApplicationController
# ...
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: "Post was successfully created." }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# ...
あれ、:unprocessable_entity
のままですね💦
これ、実はRails本体のジェネレータではなく、jbuilder gemのジェネレータが使われているせいです。
そこで、jbuilder
を消してから、もう一度scaffoldを実行してみます。
-gem "jbuilder"
bundle install
rails g scaffold Post content:text
生成されたコードはこちらです。
class PostsController < ApplicationController
# ...
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post, notice: "Post was successfully created."
else
render :new, status: :unprocessable_content
end
end
# ...
はい、今度は:unprocessable_content
が使われるようになりました!
Rails 8.0.3以上を使っていれば :unprocessable_entity
でも:unprocessable_content
でも、どっちでも警告は出なくなるとはいえ、jbuilder
の有無によってscaffoldの挙動が異なることは頭の片隅に置いといてもいいかもしれません。
(参考)
こちらに修正PRが出ているので、もしかするとjbuilderもそのうち対応されるかも?
ところで、unprocessable entityとunprocessable contentって何なん?
unprocessable entityとunprocessable contentはどちらもHTTPステータスコード422に対応する名称です。
HTTPステータスコード422の意味は以下の通りです。
HTTP の 422 Unprocessable Content はクライアントエラーレスポンスステータスコードで、サーバーがリクエストコンテンツのコンテンツ型を理解し、リクエストコンテンツの構文が正しいことを示していますが、コンテンツに格納された指示を処理することができなかったことを表します。
https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Status/422
422はもともとはunprocessable entityと呼ばれていたが(参考)、RFC 9110 (HTTP/1.1 Semantics, 2022)でunprocessable contentという名前に変わったみたいですね。
つまり、
- unprocessable entity(old)
- unprocessable content(NEW!)
というわけです。
Rack 3.1から仕様が変わったのは、この名称変更に従った結果です。
ですので、Railsでもこれから新しいコードを書くときは、:unprocessable_entity
ではなく、:unprocessable_content
を使った方がいいと思います。
まとめ
というわけで、この記事ではRailsでたまに見かける"Status code :unprocessable_entity is deprecated"みたいな警告の対処方法を説明してみました。
ざっくりまとめると、
- 最新のRailsにアップデートしよう!
- これから新規に書くコードは
:unprocessable_entity
ではなく、:unprocessable_content
を使おう!
という感じですね。
みなさん、この方針で対処していってください!