Step by Step Ruby on Rails

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

Ruby on Rails Tutorial AngularJSを使ってユーザーログインページを作成、ログイン失敗時の処理作成

「Ruby on Rails Tutorial」のサンプルアプリをAngularJSとBootstrap3を使う形にして作成します。ユーザーログイン機能を作成します。今回はまずRailsのコントローラを作成、Railsのルート設定、AngularJSのルート設定、ログインページの作成、ログイン失敗時の処理を作成します。

(1)Railsコントローラを作成、ルート設定

ユーザーログイン時にセッションも管理します。ここでは、sessionsという名前でコントローラを作成し、下記アクションを使用します。

・createアクション
ログインフォームからログイン。HTTPのPOSTリクエスト。セッションを作成。
・destroyアクション
ログアウト。HTTPのDELETEリクエスト。セッションを削除

1)Sessionsコントローラを作成

$ rails generate controller Sessions

2)セッションコントローラのcreateアクション作成

●ユーザーログイン失敗時の処理内容

①ユーザーログインフォームで入力された情報をparamsハッシュから受け取る。

②paramsで受け取ったメールアドレスをキーにユーザーをDBから検索。

③ユーザーが存在した場合、paramsで受け取ったパスワードを基に認証チェック。

④認証が失敗した場合、ログインページにエラーメッセージを表示。

●createアクション作成

入力されたメールアドレスとパスワードを基に認証し、エラーの場合はエラーメッセージを設定し、JSONフォーマットでリターンします。

$ vi app/controllers/sessions_controller.rb

  def create
    user = User.find_by(email: session_params[:email].downcase)
    if user && user.authenticate(session_params[:password])
    else
      msg = {"password" => ["Invalid email/password combination"]}
      render json: msg, status: :unprocessable_entity
    end
  end
private
  def session_params
    params.permit(:email,:password)
  end

3)Railsのルート設定

$ vi config/routes.rb

  match '/app/sessions', to: 'sessions#create',  via: 'post'
  match '/app/sessions', to: 'sessions#destroy', via: 'delete'

(2)AngularJSの$resourceのRESTアクションをサービスとして定義

Railsのサーバー側にAngularJSの$resourceサービスを使ってアクセスするアクションをサービスとして定義します。

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

myModule.factory("sessionResource", function($resource) {
  return $resource("/app/sessions",{},
    {
      'create':  { method: 'POST' },
      'destroy': { method: 'DELETE' }
    }
  );
});

(3)AngularJSのルート設定追加

ログインページ用のルート設定を追加します。

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

    .when("/signin", {
     templateUrl: "<%= asset_path('sessions/new.html.erb') %>"
     })

(4)AngularJSのコントローラを作成

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

myModule.controller("SessionsNewCtrl", function($scope, sessionResource) {
  $scope.session = new sessionResource();
  $scope.submit = function() {
    function success(response) {
      console.log("test");
    }
    function failure(response) {
      _.each(response.data, function(errors, key) {
        _.each(errors, function(e) {
          $scope.sessionNewForm[key].$dirty = true;
          $scope.sessionNewForm[key].$setValidity(e, false);
        });
      });
    }
    sessionResource.create($scope.session, success, failure);
  };
  $scope.errorMessage = function(name) {
    var s = $scope.sessionNewForm[name].$error;
    result = [];
    _.each(s, function(key, value) {
      result.push(value);
    });
    return result.join(", ");
  };
  $scope.errorClass = function(name) {
    var s = $scope.sessionNewForm[name];
    return s.$invalid && s.$dirty ? "has-error" : "";
  };
});


・ng-classを使ってバリデーションエラー時のCSS設定を追加

バリデーションエラー発生時に、動的にBootstrap3の"has-error"CSSクラスを設定します。これで、エラー発生時に入力項目が赤くなります。

・Railsのコントローラで設定したエラーメッセージをAngularJSのフォーム表示する部分は、以前作成したユーザー登録の場合と同じです。

(5)ユーザーログインフォーム作成

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

<div ng-controller="SessionsNewCtrl" class="row">
  <div class="col-md-6 col-md-offset-3">
    <h1 class="text-center">Sign in</h1>
    <div class="well">
      <form name="sessionNewForm" ng-submit="submit()" novalidate>
        <div class="form-group">
          <label>Email</label>
          <input type="email" name="email" class="form-control"
            ng-model="session.email"
            required />
        </div>
        <div class="form-group" ng-class="errorClass('password')">
          <label>Password</label>
          <input type="password" name="password" class="form-control"
            ng-model="session.password" required />
          <span class="help-block" ng-show="sessionNewForm.password.$invalid && sessionNewForm.password.$dirty">
            {\{errorMessage('password')}}
          </span>
        </div>
        <button type="submit" class="btn btn-large btn-primary">Sign in</button>
      </form>
      <p>New user?<a href="/users/new">Sign up now!</a></p>
    </div>
  </div>
</div>

6)メニューにログインのリンクを追加

$ vi app/views/layouts/_header.html.erb

<li><%= link_to "Sing in", "/signin" %></li>