「Ruby on Rails Tutorial」のサンプルアプリをAngularJSとBootstrap3を使う形にして作成します。チュートリアルでは、ログイン後にナビゲーションメニューのログインのリンクをログアウトに切替える処理を行っています。同様の処理を追加しました。
(1)ログイン済みユーザーを保持する処理をサービスに追加
ログイン済みユーザー情報は複数のコントローラからアクセスするので、ログイン済みユーザー情報をセット、取得する処理をサービスに追加しました。
フラッシュメッセージを保持するために作成したサービスに追加しました。
$ vi app/assets/javascripts/mymodule.js.erb
myModule.factory("flashService", function ($rootScope) { var currentUser = { user: {id: 0} }; return { getUser: function () { return currentUser; }, setUser: function (user) { currentUser = user; } }; });
(2)ログイン成功時にユーザー情報を保持
ログイン成功時にログインユーザー情報を上記(1)で定義したサービスに登録します。
$ vi app/assets/javascripts/mymodule.js.erb
myModule.controller("SessionsNewCtrl", function($scope, sessionResource, $location, flashService) { $scope.submit = function() { function success(response) { var user_info = response; flashService.setUser(user_info); $location.path("/users/" + response.user.id); } function failure(response) { : } sessionResource.create($scope.session, success, failure); }; ※RailsのSessionsのcreateアクション def create user = User.find_by(email: session_params[:email].downcase) if user && user.authenticate(session_params[:password]) remember_token = User.new_remember_token cookies.permanent[:remember_token] = remember_token user.update_attribute(:remember_token, User.encrypt(remember_token)) @user_info = { user: user } render json: @user_info, status: :accepted, location: user else msg = {"password" => ["Invalid email/password combination"]} render json: msg, status: :unprocessable_entity end end
(3)ナビゲーションメニューを修整
ng-hide、ng-showディレクティブを使って、ログインユーザーのIDを取得できた場合は、ログインのリンクを非表示、ログアウトのリンクを表示するようにしました。
(ビュー)
$ vi app/views/layouts/_header.html.erb
<div ng-controller="CollapseDemoCtrl" class="navbar navbar-default navbar-fixed-top" role="navigation"> : <div class="navbar-collapse" collapse="isCollapsed"> <ul class="nav navbar-nav"> : <li ng-hide="chkSignin().user.id > 0"><%= link_to "Sign in", "/signin" %></li> <li ng-show="chkSignin().user.id > 0"><%= link_to "Users", "/users" %></li> <li ng-show="chkSignin().user.id > 0" class="dropdown" dropdown> <a class="dropdown-toggle" dropdown-toggle>Account<span class="caret"></span></a> <ul class="dropdown-menu"> <li><%= link_to "Profile", "/users/{\{chkSignin().user.id}}/" %></li> <li><%= link_to "Settings", "/users/{\{chkSignin().user.id}}/edit" %></li> <li role="separator" class="divider"></li> <li><%= link_to "Sign out", "/signout" %></li> </ul> </li>
(コントローラ)
$ vi app/assets/javascripts/mymodule.js.erb
function CollapseDemoCtrl($scope, flashService) { $scope.chkSignin = function() { return flashService.getUser(); }; }
(4)ブラウザリロード後もログイン状態維持する設定
上記の処理内容ではブラウザをリロードすると無効になってしまうので、ブラウザリロードの対策を追加します。
1)runメソッドでAngularJSアプリ起動時にログイン済みユーザーを取得
①runメソッドでAngularJSアプリ起動時にsessionResourceサービスで定義した$resourceサービスを使ってサーバーからログイン済みユーザー情報を取得。
②上記①で取得したログイン済みユーザーを”flashService”サービスにセット。
③ナビゲーションメニューで”flashService”サービスからログイン済みユーザー情報を取得して、ログイン/ログアウトリンクを制御。
myModule.run(function (sessionResource,flashService) { sessionResource.current_user({}, function(response) { if (response.user && response.user.id) { var user_info = response; } else { var user_info = { user: {id: 0} }; } flashService.setUser(user_info); }); }); myModule.factory("sessionResource", function($resource) { return $resource("/app/sessions", {}, { 'create': { method: 'POST' }, 'destroy': { method: 'DELETE' }, 'current_user': { method: 'GET', isArray: false } } ); }); myModule.factory("flashService", function ($rootScope) { var currentUser = { user: {id: 0} }; return { getUser: function () { return currentUser; }, setUser: function (user) { currentUser = user; } }; });
2)Railsサーバー側にルート設定追加
$ vi config/routes.rb
match ‘/app/sessions’, to: ‘sessions#current_user’, via: ‘get’
3)Railsのコントローラにクッキーからログインユーザーを取得するアクションを追加
$ vi app/controllers/sessions_controller.rb
def current_user remember_token = User.encrypt(cookies[:remember_token]) current_user ||= User.find_by(remember_token: remember_token) @user_info = { user: current_user } render json: @user_info, status: :accepted end