💎

Railsで ActionNotFound: The action could not be found と表示される

2024/11/19に公開

問題

Railsでこのようなコードを実装しました。

class UsersController < ApplicationController

  # GET /users
  def index
    @users = User.all
    render json: @users
  end

...

  private
  def user_params
    params.require(:user).permit(
      :department_id,
      :name,
      :birthday
    )
  end

  # DELETE /users/:id
  def destroy
    @user = User.find(params[:id])

    if @user
      @user.destroy
      render json: { message: 'User deleted successfully' }, status: :no_content
    else
      render json: { error: 'User not found' }, status: :not_found
    end
  end
end

http://localhost:3000/users/1を呼び出したところ、以下のエラーが表示されました。

"status": 404,
"error": "Not Found",
"exception": "#<AbstractController::ActionNotFound: The action 'destroy' could not be found for UsersController>",

404なのでidが一致するUserが見つからなかったようでもありますが、エラー文にThe action 'destroy' could not be foundとあるので、destroyメソッドが見つからない、ということのようです。しっかり書いてるのに…

解決方法

privateの下にdestroyメソッドを記述してたのがいけなかったようです。
このように、destroyprivate以下を入れ替えたらうまく行きました。

# DELETE /users/:id
  def destroy
    @user = User.find(params[:id])

    if @user
      @user.destroy
      render json: { message: 'User deleted successfully' }, status: :no_content
    else
      render json: { error: 'User not found' }, status: :not_found
    end
  end
  
  private
  def user_params
    params.require(:user).permit(
...

原因

rubyでは、private1行だけ書くとその下に書いてあるメソッドは全てprivate扱いされるようで、他の場所から呼び出すことができなくなります。知らない仕様だった。

また、defの前にprivateを書けばこのようなことは起こりません。

private def user_params
    params.require(:user).permit(
...

この場合は下にdestroyを書いても大丈夫。

余談

Railsチュートリアルの最大手Railsをはじめようでは、privateが改行されて書かれています。

7.3.2 Strong Parametersを使う
private
    def article_params
      params.require(:article).permit(:title, :body)
    end

これを参考に書いたのでうまくいかなかったようですね…

Discussion