[RoR][勉強メモ]Deviceのユーザ登録失敗時の遷移先をカスタマイズ


記事の目的

  • RailsでDeviceを利用した時に、ユーザ登録(signup)に失敗時の遷移先を変更したかったがハマった
  • 対応方法を忘備録として記事にする
  • 結論としてはDeviceのソースコードを読むことが大事

実現したかったこと

  • 作成中のアプリケーションではトップページ(root)にユーザ登録フォームを配置
  • root_pathにregistrations_controllerのnewアクションが設定されている
  • トップページにはユーザのタイムライン投稿が表示されている

トップページのイメージ

  • トップ画面の左側にはタイムラインが表示
  • 右側にはユーザ登録用のフォームが表示される

処理のイメージ

  • バリデーションに引っかかるとかユーザ登録失敗時にトップページへリダイレクトさせたかった
  • プラスの要件としてnewメソッドを中継して描画させたい(newメソッドがタイムラインを取得する処理を担当しているため)

 実装するに当たっての課題

  • Deviceのregistrations_controller.rbの処理で失敗時にどのページをレンダリングorリダイレクトさせるのか分からなかった(=ただの調査不足)

解決方法

  • registrations_controller.rbをオーバライドして失敗時のページ遷移を書き換えるだけだった

registrations_controller.rbのcreateメソッドの処理

  • オリジナルのcreateメソッドではこんな処理のしていました
  • saveした後にレコードが存在してるいか最初のif分で判定している
  • つまりコメント部分の処理をオーバーライドしてあげることで実現が可能になると考えた
registrations_controller.rb
def create
    build_resource(sign_up_params)

    resource.save
    yield resource if block_given?
    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      #登録失敗時の処理が記述されているっぽい場所
      clean_up_passwords resource
      set_minimum_password_length
      #登録失敗時のレスポンス処理
      respond_with resource
    end
  end

書き換え後のregistrations_controller.rbのcreateメソッドの処理

  • 最後のrespond_withredirect_toに置き換えただけです
  • これよってnewメソッド経由でトップページが再度描画されるようになります
書き換え後createメソッド 
def create
    build_resource(sign_up_params)

    resource.save
    yield resource if block_given?
    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      set_minimum_password_length
      #書き換えた部分
      redirect_to action: 'new', flash:{error:"ユーザ登録に失敗しました"}
    end
  end

次の課題

  • 現在はバリデーションエラーのメッセージを渡せていないため、ユーザ側ではどこが間違えているのか分からない不親切な処理となっている
  • flash:{error: resource.errors.full_message}とかうまく処理できないか検証する

まとめ

  • deviceの処理をカスタマイズしたい場合はgithubからコードを見るのが一番早い