導入
Ruby on RailsのDeviseは強力な認証ソリューションを提供しますが、時として複数のモデルを管理する際に予期しない振る舞いに直面することがあります。今回のケーススタディでは、複数モデルでのログインを避けるための対処法を探求しました。
問題発生
あるRailsアプリケーションにて、予約確認のアクションを処理中にNoMethodError
が発生しました。
NoMethodError at /reservations/confirm
undefined method `reject' for nil:NilClass
コードの該当部分は以下の通りです:
# app/controllers/reservations_controller.rb
def confirm
...
@services = Service.where(id: reservation_params[:service_ids].reject(&:blank?))
...
end
このエラーは、reservation_params[:service_ids]
がnil
であるため、nil
にreject
メソッドを呼び出そうとした時に発生しています。
問題の解析と対処
コントローラーでのエラーハンドリング
最初のステップは、service_ids
が存在しない、または空の場合に適切なフィードバックを提供し、ユーザーをフォーム画面にリダイレクトするエラーハンドリングを追加することでした。
# app/controllers/reservations_controller.rb
def confirm
...
if reservation_params[:service_ids].nil? || reservation_params[:service_ids].empty?
flash[:alert] = "サービスが選択されていません。"
redirect_to back_to_form_path and return
end
...
end
リダイレクトとフラッシュメッセージ
しかし、リダイレクトを使用せずにrender :new
を呼び出すことにした際に、次のエラーが発生しました。
NoMethodError at /reservations/confirm
undefined method `each' for nil:NilClass
修正:必要なインスタンス変数のセット
render
メソッドを使用する際には、フォームのビューで必要な全てのインスタンス変数をセットする必要があります。そこで、以下のようにエラーハンドリングを修正しました。
# app/controllers/reservations_controller.rb
def confirm
...
if reservation_params[:service_ids].nil? || reservation_params[:service_ids].empty?
flash.now[:alert] = "サービスが選択されていません。"
set_variables_for_form
render :new and return
end
...
end
private
def set_variables_for_form
@categories = Category.all
...
end
結果
上記の修正を施した結果、ユーザーがサービスを選択せずに確認画面へ遷移しようとすると、適切にフォーム画面に戻され、フラッシュメッセージで「サービスが選択されていません」というアラートが表示されるようになりました。