2

RoR バックエンドを使用して AngularJS アプリケーションを開発していますが、複数のレイアウトを使用しているときに問題が発生しました。アプリケーションは、認証されていないユーザーにページをレンダリングするときに 1 つのレイアウトを使用し、ユーザーが認証されると別のレイアウトに変更します。

レイアウトは最初のページロード時にサーバーであり、Rails によって管理されます。ルートに基づいてさまざまなレイアウトをロードする方法を示すサンプル コード:

class SampleController < ApplicationController
  layout :current_layout

  def current_layout
    "layout" unless request.xhr?
  end
end

別のセクションのサンプル コントローラー:

class SampleController2 < ApplicationController
  layout :current_layout

  def current_layout
    "anotherLayout" unless request.xhr?
  end
end

これは、認証されたユーザーと認証されていないユーザーを管理するコントローラーに対して個別に定義され、基本的に適切なレイアウトを提供します。Angular が登場したときのルーティング ループを防ぐために、XHR チェックを使用しています。

したがって、これはほとんどのブラウザーで正常に機能しますが、IE9 を使用すると壊れます。Angular は #! の使用にフォールバックします。IE9 の URL。Rails は、ハッシュがバックエンドに送信されないため、どのコントローラーをロードするかわかりません。この場合、Rails はルートとそれに関連付けられたレイアウトを読み込みます。認証済みセクションがデフォルトとして設定されている場合、認証されていないユーザーに対してもこのレイアウトが読み込まれます。その逆も同様です。

したがって、基本的には、HTML5 pushState をサポートしていないブラウザーでも、この複数レイアウト アプリケーションが適切に動作するようにする方法を見つける必要があります。これに対する適切な解決策をあちこちでチェックしましたが、まだ何も思いつきませんでした。

4

1 に答える 1

2

クライアント側とサーバー側の両方で多くの調整をテストした後、次のソリューションを使用することになりました。基本的に、Angular を複数のレイアウトに公開するのをやめて、Rails で処理しました。もちろん、これはユーザーに制限を課します。

アプリは、ダッシュボード認証の 2 つの主要なセクションに分かれています。したがって、バックエンドでは、ユーザーがログインしている場合は認証ページにアクセスできないように制限し、ユーザーが認証されている場合にのみダッシュボードページにアクセスできるようにします。

問題の根本は、レイアウトを提供する必要がある場合、Rails がどのレイアウトを提供するかを知る方法がなかったことです。Cookie を使用して、認証されたユーザーと認証されていないユーザーを区別しました。Cookie が設定されていて、信頼性テストに合格すると、ダッシュボード レイアウトが読み込まれます。そうしないと、ダッシュボードにアクセスしようとするすべてのユーザーが認証セクションにリダイレクトされます。

class DashboardController < ApplicationController

  layout :current_layout

  before_filter :authenticate_user

  def authenticate_user
    if request.xhr? && !cookies[:access_token]
      redirect_to "/login"
    end
  end

  def current_layout
    if cookies[:access_token]
      "dashboard" unless request.xhr?
    else 
      "application" unless request.xhr?
    end
  end
end

認証セクションについても同様です。

class AuthenticationController < ApplicationController

  layout :current_layout

  before_filter :redirect_if_authenticated

  def redirect_if_authenticated
    if request.xhr? && cookies[:access_token]
      redirect_to "/dashboard"
    end
  end

  def current_layout
    if cookies[:access_token]
      "dashboard" unless request.xhr?
    else 
      "application" unless request.xhr?
    end
  end
end

したがって、ここで注意すべき主な点は次のとおりです。

  • リクエストが XHR の場合は、レイアウトを再度提供しないでください。レイアウトを再度提供すると、IE9 で無限の読み込みループが発生し、他の IE バージョンでも同様に発生する可能性があります。

  • サーバー側で URL フラグメントを取得していないため、どのレイアウトをロードする必要があるかを知る方法がありません。そのため、Cookie を信頼できる情報源として使用しており、アクセスはこれのみに基づいて制御されています。

  • これにより、クライアント側に非対称性が生じます。場合によっては、ユーザーが別のセクションの URL を入力すると、URL とレイアウトがそのまま残ります。サーバーからの URL に基づいて何もできないため、この場合 Cookie は変更されないため、これは Angular で処理する必要があります。

最後のポイントとして、私の場合の認証セクションにはいくつかの可能な URL しかなかったので、次のように正規表現の一致を取得した場合にリダイレクトしました。

if(Modernizr.history) {
    if(!/(login|sign|pass)/.test(location.pathname)) {
        $location.path('/');
    }
} else {
    if(location.hash.length > 3 && !/(login|sign|pass)/.test(location.hash)) {
        $window.location.href = '/';
    }
}

ここで APIをチェックするとhistory、古い IE ブラウザーでは (他の古いブラウザーでもそうだと思いますが?)、$location.path('/')一貫してページ全体をリロードしていませんでした。これを使用する場合、$routeProvider構成は root にリダイレクトする場合に備えて、条件付きでレイアウトもロードする必要があります/

$routeProvider
// Code for routes
.otherwise({
  // Of course, add something to check access_token authenticity here as well :P
  redirectTo: $.cookie('access_token') ? "/dashboard" : "/login"
});

したがって、これらのいくつかの調整により、アプリはすべてのブラウザーで適切に機能し、複数のレイアウトで機能します. もちろん、私は RoR について何も知らないので、誰かが提案するいくつかの改善、またはより良い答えを期待しています。;)

于 2013-07-30T06:36:50.653 に答える