Step by Step Ruby on Rails

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

Ruby on Rails Tutorial AngularJSを使ってユーザー登録機能を作成

「Ruby on Rails Tutorial」のサンプルアプリをAngularJSとBootstrap3を使う形にして作成します。AngularJSを使ってユーザー登録機能を作成します。

(1)Railsユーザーモデルにhas_secure_passwordを使って暗号化パスワード認証の機能追加

1)概要

・bcriptを使ってパスワードをセキュアなハッシュとして保存できます。

・ユーザー作成時のパスワード存在チェック、パスワードの確認入力チェックのバリデーションが自動で追加されます。

・bcrypt-rubyをインストールをインストールする必要があります。

・テーブルに"password_digest"カラムを追加する必要があります。

2)設定手順

①bcrypt-rubyをインストール

$ vi Gemfile

gem 'bcrypt'

$ bundle install

②usersテーブルに"password_digest"カラムを追加

$ rails generate migration add_password_digest_to_users password_digest:string
      invoke  active_record
      create    db/migrate/20150713044621_add_password_digest_to_users.rb

設定内容確認を確認します。

$ more db/migrate/20150713044621_add_password_digest_to_users.rb

class AddPasswordDigestToUsers < ActiveRecord::Migration
  def change
    add_column :users, :password_digest, :string
  end
end

③マイグレーション実行

$ bundle exec rake db:migrate

④Userモデルに"has_secure_password"メソッド追加

"has_secure_password"によって"password"と"password_confirmation"属性が自動で追加され、存在チェックのバリデーションも設定されます。

$ vi app/models/user.rb

class User < ActiveRecord::Base
  has_secure_password
end

3)Railsコンソールで動作確認

①ユーザー登録

2.0.0p247 :004 > test = User.create(name: "testuser4", email: "test4@example.com", password: "test4pass", password_confirmation: "test4pass")
 => #<User id: 4, name: "testuser4", email: "test4@example.com", created_at: "2015-07-13 04:51:06", updated_at: "2015-07-13 04:51:06", password_digest: "$2a$...">

②登録されたパスワードを表示

2.0.0p247 :005 > user = User.find_by(email: "test4@example.com")

2.0.0p247 :006 > user.password_digest
 => "$2a$..."

③誤ったパスワードで認証

2.0.0p247 :007 > user.authenticate("invalid")
 => false

④正しいパスワードで認証

2.0.0p247 :008 > user.authenticate("test4pass")
 => #<User id: 4, name: "testuser4", email: "test4@example.com", created_at: "2015-07-13 04:51:06", updated_at: "2015-07-13 04:51:06", password_digest: "$2a$...">

(2)AngularJSのパーシャルビューを使ってユーザー登録ページ作成

1)AngularJSのルート設定にnewを追加

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

myModule = angular.module('myModule', ['ui.bootstrap','ngRoute','ngResource']);

myModule.config(function($routeProvider, $locationProvider) {
  $locationProvider.html5Mode(true);
  $routeProvider
:
    .when("/users/new", {
     templateUrl: "<%= asset_path('users/new.html.erb') %>"
     })


2)newページのテンプレートを追加

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

<div ng-controller="UsersNewCtrl" class="row">
  <div class="col-md-6 col-md-offset-3">
    <h1 class="text-center">Sign up</h1>
    <form name="userNewForm" novalidate>
      <div class="well">
        <div class="form-group">
          <label>name</label>
          <input name="name" class="form-control"
            ng-model="user.name" required />
        </div>
        <div class="form-group">
          <label>email</label>
          <input type="email" name="email" class="form-control"
            ng-model="user.email" required />
        </div>
        <div class="form-group">
          <label>password</label>
          <input type="password" name="password" class="form-control"
            ng-model="user.password" required />
          </div>
        <div class="form-group">
          <label>password_confirmation</label>
            <input type="password" name="password_confirmation" 
              class="form-control"
              ng-model="user.password_confirmation" required />
        </div>
        <button ng-click="submit()" class="btn btn-primary">
          Create my account
        </button>
      </div>
    </form>
  </div>
</div>


3)newページに対応するAngularJSコントローラ"UsersNewCtrl"を定義

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

myModule.controller("UsersNewCtrl", function($scope, userResource) {
  $scope.user = new userResource();
});

4)ホームページにnewページへのリンク追加

$ vi app/assets/templates/static_pages/home.html.erb

<p class="text-center">
  <a class="btn btn-large btn-primary" href="/users/new">Sign up now!</a>
</p>

(3)AngularJSの$resourceサービスでPOST送信、Railsでデータ保存

1)AngularJSの$resourceサービスを使ってPOST送信

・"userResource"サービスを使ってPOST送信を行う関数を追加。

・ユーザー登録成功時は、ユーザーshowページへ遷移

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

myModule.factory("userResource", function($resource) {
  return $resource("/app/users/:id", { id: "@id" },
    {
      'create':  { method: 'POST' },
:
    }
  );
});

mymodule.controller("UsersNewCtrl", function($scope, userResource, $location) {
  $scope.user = new userResource();
  $scope.submit = function() {
    function success(response) {
      $location.path("/users/" + response.id);
    }
    function failure(response) {
      console.log("failure", response)
    }
    userResource.create($scope.user, success, failure);
  };
});

2)Railsコントローラを設定

$ vi app/controllers/users_controller.rb

  def create
    @user = User.new(user_params)
    if @user.save
      render json: @user, status: :created, location: @user
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end

private
  def user_params
    params.permit(:name:email,:password,:password_confirmation)
  end

3)CSRF対策

この状態でHTTP POSTリクエストを送信すると下記エラーが発生します。

Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 1ms

上記を回避するためHTTPヘッダーにデフォルトでCSRFトークンを付与するように設定します。

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

myModule.config(function($httpProvider) {
  $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
});

4)動作確認

ユーザー登録フォームからユーザー登録し、ユーザーshowページに遷移することを確認する。