misakiyashima / graduation_exam

0 stars 0 forks source link

新規登録・ログイン・ログアウト機能の実装とデバッグについて #60

Open misakiyashima opened 1 week ago

misakiyashima commented 1 week ago

●実装したいもの・解決したいもの(なるべく小さい粒度で記載してください)  ・新規登録の成功とログインの成功  ・ログアウト時のエラー改善 ●エラー内容  一度、通常通りに新規登録・ログイン機能の実装に成功しておりましたが、ログアウト機能でエラーが続いている状況でした。  具体的には、ログアウトボタンを押してもルーティングエラーとなり、なぜかgetリクエストが送信されているようなが状態でした。ルーティングファイルにてgetリクエストが送信されていないことの確認をはじめ、コントローラのログアウト機能の設定やその他のファイルも確認していきましたが、最後まで原因がはっきりと判明できずにいました。ネットの情報を参考に、webpackをアップデートすることで同じようなエラーが改善された例があったため、webpackをアップデートしてみましたが、また別のmap関数の定義についてなどjavascriptファイル関連のエラーが続くようになり、webpackをアップデートする前まで機能していた新規登録・ログイン機能も機能しない状態になってしまいました。  chat-gptに聞きつつ、エラーに該当するjavascriptファイルのクラスを何度も修正していますが、同じようなエラーが毎回続き、解決できずにおります。 ●エラーの意味とエラー内容から推測される原因 application-28c7c0b1…cc30b034eaa.js:3382 Uncaught SyntaxError: Identifier '#getActionForFormSubmission' has already been declared (at application-28c7c0b1…30b034eaa.js:3382:3)

→#getActionForFormSubmission プライベート フィールドが既に宣言されているために発生? 重複を避けるように修正してみておりますが、エラーは変わらずになっています、、

また、該当と思われるjavascriptファイルは下記になります。aap/assets/builds/application.js 3232行目~3412行目

var Navigator = class {
  #getActionForFormSubmission;
  #getDefaultAction;

  constructor(delegate) {
    this.delegate = delegate;
    this.#getActionForFormSubmission = (formSubmission, fetchResponse) => {
      // フィールドの初期化
      // ここに実際のロジックを追加します
    };
    this.#getDefaultAction = (fetchResponse) => {
      const sameLocationRedirect = fetchResponse.redirected && fetchResponse.location.href === this.location?.href;
      return sameLocationRedirect ? "replace" : "advance";
    };
  }

  proposeVisit(location2, options = {}) {
    if (this.delegate.allowsVisitingLocationWithAction(location2, options.action)) {
      this.delegate.visitProposedToLocation(location2, options);
    }
  }

  startVisit(locatable, restorationIdentifier, options = {}) {
    this.stop();
    this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, {
      referrer: this.location,
      ...options
    });
    this.currentVisit.start();
  }

  submitForm(form, submitter) {
    this.stop();
    this.formSubmission = new FormSubmission(this, form, submitter, true);
    this.formSubmission.start();
  }

  stop() {
    if (this.formSubmission) {
      this.formSubmission.stop();
      delete this.formSubmission;
    }
    if (this.currentVisit) {
      this.currentVisit.cancel();
      delete this.currentVisit;
    }
  }

  get adapter() {
    return this.delegate.adapter;
  }

  get view() {
    return this.delegate.view;
  }

  get rootLocation() {
    return this.view.snapshot.rootLocation;
  }

  get history() {
    return this.delegate.history;
  }

  // Form submission delegate
  formSubmissionStarted(formSubmission) {
    if (typeof this.adapter.formSubmissionStarted === "function") {
      this.adapter.formSubmissionStarted(formSubmission);
    }
  }

  async formSubmissionSucceededWithResponse(formSubmission, fetchResponse) {
    if (formSubmission == this.formSubmission) {
      const responseHTML = await fetchResponse.responseHTML;
      if (responseHTML) {
        const shouldCacheSnapshot = formSubmission.isSafe;
        if (!shouldCacheSnapshot) {
          this.view.clearSnapshotCache();
        }
        const { statusCode, redirected } = fetchResponse;
        const action = this.#getActionForFormSubmission(formSubmission, fetchResponse);
        const visitOptions = {
          action,
          shouldCacheSnapshot,
          response: { statusCode, responseHTML, redirected }
        };
        this.proposeVisit(fetchResponse.location, visitOptions);
      }
    }
  }

  async formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
    const responseHTML = await fetchResponse.responseHTML;
    if (responseHTML) {
      const snapshot = PageSnapshot.fromHTMLString(responseHTML);
      if (fetchResponse.serverError) {
        await this.view.renderError(snapshot, this.currentVisit);
      } else {
        await this.view.renderPage(snapshot, false, true, this.currentVisit);
      }
      if (!snapshot.shouldPreserveScrollPosition) {
        this.view.scrollToTop();
      }
      this.view.clearSnapshotCache();
    }
  }

  formSubmissionErrored(formSubmission, error2) {
    console.error(error2);
  }

  formSubmissionFinished(formSubmission) {
    if (typeof this.adapter.formSubmissionFinished === "function") {
      this.adapter.formSubmissionFinished(formSubmission);
    }
  }

  // Visit delegate
  visitStarted(visit2) {
    this.delegate.visitStarted(visit2);
  }

  visitCompleted(visit2) {
    this.delegate.visitCompleted(visit2);
    delete this.currentVisit;
  }

  locationWithActionIsSamePage(location2, action) {
    const anchor = getAnchor(location2);
    const currentAnchor = getAnchor(this.view.lastRenderedLocation);
    const isRestorationToTop = action === "restore" && typeof anchor === "undefined";
    return action !== "replace" && getRequestURL(location2) === getRequestURL(this.view.lastRenderedLocation) && (isRestorationToTop || anchor != null && anchor !== currentAnchor);
  }

  visitScrolledToSamePageLocation(oldURL, newURL) {
    this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
  }

  // Visits
  get location() {
    return this.history.location;
  }

  get restorationIdentifier() {
    return this.history.restorationIdentifier;
  }

  #getActionForFormSubmission(formSubmission, fetchResponse) {
    const { submitter, formElement } = formSubmission;
    return getVisitAction(submitter, formElement) || this.#getDefaultAction(fetchResponse);
  }
};

function fetchWithReturn(url, options) {
  let map = new Map(); // これでMapオブジェクトを作成します
  map.set('key', 'value'); // setメソッドで値を設定します

  let values = map.get('key'); // getメソッドで値を取得します
  console.log(values); // 'value'

  return nativeFetch(url, {
    ...options,
  });
}

function fetchWithTurboHeaders(url, fetchOptions) {
  let map = new Map(); // これでMapオブジェクトを作成します
  map.set('key', 'value'); // setメソッドで値を設定します

  let values = map.get('key'); // getメソッドで値を取得します
  console.log(values); // 'value'

  return nativeFetch(url, {
    ...fetchOptions,
  });
}

// この行を関数の内部に移動します
function someFunction() {
  this.response = fetchWithTurboHeaders(this.url.href, fetchOptions);
}

●実装する際に参考にした資料  ランテックカリキュラム rails基礎 ●エラーを解決するために調べた資料  https://qiita.com/bumbun-blau/items/456f8015e304664f27d2

TakenakaEri commented 1 week ago

お疲れ様です! 一つ一つ整理してみました。GitHubをcloneして手元で動かしてみたのですが、うまく動かず...yarn installしたり、少々強引に動かしたので、私の開発環境と少々異なるかもしれませんが...

issueのみでFile Changedにコメントできないので、以下をご確認ください。

app/views/layouts/application.html.erb こちら、私の手元ではエラーが出ていたので、<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>を削除しました。

また、の閉じタグの前にの開始タグが始まっていたので、一旦整理しました。

<!DOCTYPE html>
<html>
  <head>

    <title><%= content_for(:title) || "allinclusive" %></title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="mobile-web-app-capable" content="yes">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= yield :head %>

    <link rel="manifest" href="/manifest.json">
    <link rel="icon" href="/icon.png" type="image/png">
    <link rel="icon" href="/icon.svg" type="image/svg+xml">
    <link rel="apple-touch-icon" href="/icon.png">
    <%= stylesheet_link_tag "styles", "data-turbo-track": "reload" %>
  </head>

   <body>

    <header>
        <% if logged_in? %>
          <%= render 'home/header/header' %>
        <% else %>
          <%= render 'home/header/before_login_header' %>
        <% end %>

      <% if flash[:notice] %>
        <div class="alert alert-success">
          <%= flash[:notice] %>
        </div>
      <% end %>
      <% if flash[:alert] %>
        <div class="alert alert-danger">
          <%= flash[:alert] %>
        </div>
      <% end %>

    </header>

    <main>
      <%= yield %>
    </main>

   <%= render 'home/footer/footer' %> <!-- フッターをレンダリング -->
 </body>
</html>

app/controllers/users_controller.rb こちら、私の手元ではエラーが出ていたので、「flash[:notice] = "登録が完了しました。”」を「flash = "登録が完了しました。"」に変更しました。

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
     flash = "登録が完了しました。"
      redirect_to root_path
    else
      flash.now.alert = "登録に失敗しました。もう一度確認をお願いします"
      render :new
    end
  end

  private

  def user_params
    params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
  end
end

app/controllers/sessions_controller.rb destroyメソッドのroot_urlになっていた箇所をroot_pathに変更

class SessionsController < ApplicationController
  def new
  end

  def create
    @user = login(params[:email], params[:password])

    if @user.present?
      session[:user_id] = @user.id
      redirect_to root_path, notice: "ログインしました"
    else
      flash.now.alert = "ユーザー登録がありません"
      render :new
    end
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_path, notice: "ログアウトしました"
  end
end

app/views/home/header/_header.html.erb Rails7ではTurboがデフォルトの設定になっているため、deleteメソッドに設定しました。(deleteリクエストが送られるようにする) (aタグもリンク化されていなかったので、一旦コメントアウトしました)

    <header>
      <nav>
        <ul>
          <li><%= link_to 'オールインクルーシブとは?', explanation_path %></li>
                    <!--
          <li><a>旅ログ</a></li>
          <li><a>施設登録</a></li>

          <li><%= link_to 'ログアウト', logout_path, method: :delete %></li>
          -->
          <li><%= button_to 'ログアウト', logout_path, method: :delete, data: { turbo: true } %></li>
        </ul>
      </nav>
    </header>

上記内容で私の方ではログアウトできるようになったので、一旦試してみてください。

misakiyashima commented 1 week ago

お世話になっております。八嶋です。 早速ご教授いただきありがとうございます。 ご教授いただいた内容をもとに再度修正をしてみたのですが、また新規登録・ログインが成功せず、登録ボタンをおすと、設定中のフラッシュメッセージ"登録に失敗しました。もう一度確認をお願いします"が表示されます。 そのため、まだログアウトが成功するかをかくにんできずにおります、、 コンソールに表示されていた、JavaScriotファイル関連のエラーはでなくなりました! 引き続きデバッグを行っておりますが、検討箇所ございましたら引き続きご教授をいただけますと幸いです、、