Edited at

deviseを使ってみる

More than 3 years have passed since last update.

Ruby on Railsの勉強を始めました。

deviseというユーザー認証系の便利なGemがあるとのことで、今回使用してみました。

ご参考にしていただければと思います。


準備

$ rails new rails_devise

$ cd rails_devise
$ bundle install --path=vendor/bundle

新規プロジェクトの作成と、初期のGemをインストールしました。

ついでにGitで管理もしたいので、Githubにリポジトリを作成しました。

SourceTreeとGithubでGitの練習環境をつくる

$ git init

$ git remote add origin git@github.com:naoki85/rails_devise.git
$ git add .
$ git commit -m "first commit"

ここでリモートブランチにREADME.mdを先に作成しているとpushするときに怒られるようです。

そのため、リモートのマスターブランチをマージします。

$ git pull origin master

# コンフリクトを解決
$ git add .
$ git commit -m "resolved conflict"
$ git push origin master


deviseのインストール

deviseをGemfileに追加します。


Gemfile

+ # Use Devise for Authentication

+ gem 'devise'

そしてインストールします。

$ bundle install

さて、ここからdeviseを実装していきます。

(参考資料:公式のGithub

$ rails generate devise:install

インストールすると、何やら注意文が出てきました。

以下のページの執筆者の方が日本語訳してくださっておりましたので、そちらに従って対応します。

[Rails] deviseの使い方

その前に、vendor/bundle以下のファイル.gitignoreに追加し、コミットさせないようにします。

(差分が見えづらくなるので。)


.gitignore

+ # Ignore bundler gems.

+ vendor/bundle


デフォルトURLの指定

今回はローカル環境で試すだけなので、localhost:3000を指定します。


config/environments/development.rb

+ # mailer setting

+ config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }


root_urlの指定

http://localhost:3000にアクセスしたとき呼ばれるページの指定をします。

参考にさせていただいているページと同様、まだコントローラーも作成していなかったため、ここで作成します。

$ rails g controller Pages index show

これでコントローラーが作成できたので、routes.rbに記載します。


config/routes.rb

+ root 'pages#index'

+ get 'pages/show'


Flashメッセージの設定

Flashメッセージが表示される場所を追記します。

以下の文そのままで良いようです。


views/layouts/application.html.erb

<body>

+ <p class="notice"><%= notice %></p>
+ <p class="alert"><%= alert %></p>
<%= yield %>
</body>


Viewの作成


Deviseの導入で追加されるViewは、以下のコマンドを実行しなければデザインを変更できないので、デザインをカスタマイズするためにも実行します。

[Rails] deviseの使い方


$ rails g devise:views


モデルの作成

devise用のモデルを作成し、マイグレーションを走らせます。

(モデル名は任意です。)

$ rails g devise Admin_User

$ rails db:migrate

マイグレーションファイルは以下のようになっております。

デフォルトでコメントアウトされている部分もオープンにできますが、今回はライトに作りたいため、デフォルトのままでいきます。

class DeviseCreateAdminUsers < ActiveRecord::Migration[5.0]

def change
create_table :admin_users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""

## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at

## Rememberable
t.datetime :remember_created_at

## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip

## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable

## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at

t.timestamps null: false
end

add_index :admin_users, :email, unique: true
add_index :admin_users, :reset_password_token, unique: true
# add_index :admin_users, :confirmation_token, unique: true
# add_index :admin_users, :unlock_token, unique: true
end
end

また、モデルも同様に、最初から使用できるモジュールと、任意で設定するモジュールがあります。


admin_user.rb

class AdminUser < ApplicationRecord

# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end

今回はデフォルトなので、初めから使用できる下記のモジュールを使用します。

(参考資料:Railsの第4世代認証エンジンDeviseのREADMEを翻訳してみた

モジュール名
役割

Database Authenticatable
ユーザーがサインインする時に認証するためにパスワードをデータベースに暗号化し保存します。この認証は POST リクエストまたはBasic認証を通して行われます。

Registerable
登録プロセスを通してサインアップを処理します。また、アカウントを編集・削除できるようにします。

Recorverble
パスワードをリセットし、リセットの指示を送ります。

Rememberable
ユーザーを記憶するために、保存されたクッキーから、トークンを生成・消去を扱います。

Trackable
サインインのカウント・タイムスタンプ・IPアドレスを計測します。

Validatable
Eメールとパスワードによる確認を提供します。これは、オプションでカスタマイズできるので、あなた専用の確認を定義できます。

ここまでで、とりあえずrails sでローカルサーバーを起動させ確認してみると、特に何もありません。(当たり前ですが。。。)

スクリーンショット 2016-09-22 19.20.03.png


ヘルパーの実装

ユーザーがログインしていなければリダイレクトさせるのは、下記をpages_controller.rbに追記します。


controllers/pages_controller.rb

class PagesController < ApplicationController

+ before_action :authenticate_admin_user!

def index
end

# ...


再度、ページにアクセスしてみると、下記のようにリダイレクトされます。

スクリーンショット 2016-09-22 20.16.11.png

このビューは、views/devise/sessions/new.html.rbになります。

rails routesで確認できます。)

とりあえず新規登録をしてみると、下図のようにログインまでしてくれます。

ただ、ログインしていないと無条件でリダイレクトされるのも微妙なので、indexにはログインしていなくてもアクセスできるようにし、showにはログインしていないとアクセスできないようにします。

スクリーンショット 2016-09-22 20.30.36.png


showだけログインしていないとアクセスできないようにする


controllers/pages_controller.rb

class PagesController < ApplicationController

- before_action :authenticate_admin_user!
+ before_action :authenticate_admin_user!, only: [:show]

def index
end

# ...



ログイン後のリダイレクト先を変更する

after_sign_in_path_forafter_sign_out_path_forで上書きしてしまうようです。

必ず呼ばれるapplication_controller.rbに記述します。

(参考資料:ログイン後にマイページに飛ばす:Rails devise


controllers/application_controller.rb

class ApplicationController < ActionController::Base

protect_from_forgery with: :exception

+ def after_sign_in_path_for(resource)
+ pages_show_path
+ end
end



ログインとログアウトのリンクを設置する

ログインするのもログアウトするのもリンクがあると楽なので、簡単に設置してしまいます。


views/layouts/application.html.erb

<body>

+ <%= link_to 'Login', new_admin_user_session_path, method: :get %>
+ <%= link_to 'Logout', destroy_admin_user_session_path, method: :delete %>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

<%= yield %>
</body>



ログインしている場合としていない場合でリンクを出し分ける

他にも便利なヘルパーがあり、user_signed_in?でログインしているかどうかの結果を返してくれます。

(ただし、今回はモデル名をAdmin_Userにしたため、下記のサンプルの中ではadmin_user_signed_in?となっています。)

これで、ログインとログアウトのリンクを出し分けたいと思います。


views/layouts/application.html.erb

-    <%= link_to 'Login', new_admin_user_session_path, method: :get %>

- <%= link_to 'Logout', destroy_admin_user_session_path, method: :delete %>
+ <% if admin_user_signed_in? %>
+ <%= link_to 'Logout', destroy_admin_user_session_path, method: :delete %>
+ <% else %>
+ <%= link_to 'Login', new_admin_user_session_path, method: :get %>
+ <% end %>


ログインしているユーザーの情報を取得

こちらはcurrent_userでオブジェクトを取得できます。

(ただし、今回はモデル名をAdmin_Userにしたため、下記のサンプルの中ではcurrent_admin_userとなっています。)

また、user_sessionで現在のセッション情報を取得できるようですが、初期状態は空っぽです。

(何も入れていないので当たり前ですが。。。)


views/pages/show.html.erb

-<h1>Pages#show</h1>

-<p>Find me in app/views/pages/show.html.erb</p>
+<h1>Hi!!<%= current_admin_user.email %>!!</h1>
+<p><%= debug(admin_user_session) %></p>


最後に

今回、モデル名をUserではなく、Admin_Userにしたため、基本ヘルパーのuserの部分をadmin_userにする必要がありました。

モデル名をUser以外にしようとしている方は要注意です。

ビューが少し寂しいので、Bootstrapで少し整えたいと思います。