Step by Step Ruby on Rails

Ruby on Railsで実際にWebサイトを構築する手順をまとめています。

Ruby on Rails Tutorial 未ログインユーザーは編集不可にする

「Ruby on Rails Tutorial」のサンプルアプリをAngularJSとBootstrap3を使う形にして作成します。前回ユーザー編集機能を追加しました。メニューにあるユーザ編集へのリンクはログインしていないと表示しないようにしていますが、ブラウザのアドレス欄に直接ユーザー編集のURLを入力するとユーザー編集画面を表示できてしまいます。出来ないように修正します。

(1)Railsコントローラ側の設定

beforeフィルターを使って、"update"アクション実行時には、ログイン済みか確認し、ログインしていない場合は更新を実施しないように設定します。

Usersコントローラにbeforeフィルターを定義します。

$ vi app/controllers/users_controller.rb

class UsersController < ApplicationController
  before_action :signed_in_user, only: [:update]

  private
    def signed_in_user
      remember_token = User.encrypt(cookies[:remember_token])
      current_user ||= User.find_by(remember_token: remember_token)
      if current_user.nil?
        render status: :unauthorized
      end
    end

(2)AngularJSコントローラを修正

flashServiceでログイン済みのユーザー情報を保持しているので、これを利用して確認します。

ログインしていない場合は、フラッシュメッセージを設定し、ログイン画面に遷移させます。

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("UsersNewCtrl", function($scope, userResource, $location, flashService, $routeParams) {
  if ($routeParams.id) {
    if (flashService.getUser().user.id > 0 ) {
      var msg = "Profile updated";
      $scope.title = "Update your profile";
      $scope.btn_name = "Save changes";
      userResource.show({ id: $routeParams.id }, function(user_info) {
        $scope.user = user_info.user;
        $scope.gravatar_url = user_info.gravatar_url;
      })
    } else {
      var msg = "Please sign in.";
      flashService.push(msg);
      $location.path("/signin");
    }
  } else {

3)ログイン画面にフラッシュメッセージ表示

上記で設定した"Please sign in."というメッセージを定義済みのflashServiceを使って表示するように修整します。

●ビュー

$ vi app/assets/templates/sessions/new.html.erb

<div ng-controller="SessionsNewCtrl" class="row">
  <div class="col-md-6 col-md-offset-3">
    <div class="bg-warning" ng-show="getMessage()">
      <p>{\{getMessage()}}</p>
    </div>
    <h1 class="text-center">Sign in</h1>

●コントローラ

$ vi app/assets/javascripts/mymodule.js.erb

myModule.controller("SessionsNewCtrl", function($scope, sessionResource,$location,flashService) {
  $scope.getMessage = function() {
    return flashService.get();
  };
});

(3)ブラウザリロード対応

上記2)の設定だと編集画面を表示した状態でブラウザをリロードするとログイン済み情報の取得のタイミングが遅れ、ログイン済み状態でもログイン画面に遷移してしまいます。

AngularJSの$qサービスを使って修正します。

●処理の流れ

1)$qサービスを使ってログイン済み情報取得

①AngularJSで保持済み情報取得
②上記①で取得できなかった場合、サーバーから取得。

2)$qサービスで取得したログイン済み情報を使って登録・編集処理

myModule.controller("UsersNewCtrl", function($scope, userResource, $location, flashService, $routeParams, sessionResource, $q) {
  var msg = "";
  var qgetUser = function(deferred) {
    if (flashService.getUser()) {
      var quser_info = flashService.getUser();
      deferred.resolve(quser_info);
    } else {
      sessionResource.current_user({}, function(response) {
        if (response.user.id) {
          var quser_info = response;
        } else {
          var quser_info = { user: {id: 0} };
        }
        flashService.setUser(quser_info);
        deferred.resolve(quser_info);
      });
    }
  }
  var deferred = $q.defer();
  deferred.promise.then(function (result) {
    var user_info = result;
    if ($routeParams.id) {
      if (user_info.user.id > 0) {
        msg = "Profile updated";
        $scope.title = "Update your profile";
        $scope.btn_name = "Save changes";
        userResource.show({ id: $routeParams.id }, function(user_info) {
          $scope.user = user_info.user;
          $scope.gravatar_url = user_info.gravatar_url;
        })
      } else {
        msg = "Please sign in.";
        flashService.push(msg);
        $location.path("/signin");
      }
    } else {
      msg = "Welcome to the Sample App!";
      $scope.title = "Sing up";
      $scope.btn_name = "Create my account";
      $scope.user = new userResource();
    }
  },function (reason) {
    console.log("qgetUser-Error");
  })
  qgetUser (deferred);