Ruby on Rails でログイン画面を作る
前回の続きです。
構築した環境でログイン画面とユーザー一覧画面を作成していきます。
bcrypt 導入
今回のログイン画面ではメールアドレスとパスワードを入力します。
パスワードは暗号化して保存するのが今となっては当たり前なので、Railsのパスワード暗号化で一般的に使われる bcrypt を導入します。
Gemfile編集
フォルダ内の Gemfile を開き、以下の2行を追加します。
# 暗号化
gem 'bcrypt'
ビルド実行、サービス起動
フォルダ内で以下を実行します。
$ docker-compose build
ビルドが終わったらサービスを起動します。
$ docker-compose up
scaffold でユーザー画面を作成
scaffoldとは
Ruby on Rails にはMVCとCRUDのひな型を作成してくれる「scaffold」という機能があります。
- MVC・・・モデル/ビュー/コントローラ
- CRUD・・・生成(Create)/読み取り(Read)/更新(Update)/削除(Delete)
scaffold はマスタ管理画面を作ってくれる機能。と表現するとわかりやすいでしょうか。
コンテナの確認
前述のとおり scaffold は Rails の機能なので、実行するためには Rails が動いているコンテナに入る必要があります。
コマンドプロンプトをもうひとつ開き、フォルダ内で以下を実行します。
$ docker-compose ps
以下のように表示されるので、「web_1」と付いている方の「Name」をメモします。
Name Command State Ports
--------------------------------------------------------------------------------------------
railstest_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3316->3306/tcp, 33060/tcp
railstest_web_1 bundle exec rails s -p 300 ... Up 0.0.0.0:3000->3000/tcp
コンテナに入る
フォルダ内で以下を実行します。
$ docker exec -it [メモしたweb_1] /bin/bash
以下のように表示されるはずです。
(「487085381b8f」部分は環境により可変)
root@487085381b8f:/myapp#
scaffold
コンテナに入れたので、scaffold してみましょう。
以下を実行します。
rails g scaffold User name:string email:string password_digest:string
上記をざっくり説明すると
- User という画面を作る。
- User で扱うデータは name(string型)、email(string型)、password_digest(string型)の3つ。
という事になります。
データはそのままでは使えない(テーブルは作成されていない)ので、コンテナ内で以下を実行します。
rails db:migrate
画面確認
画面が表示されるか確認してみましょう。
ブラウザで http://localhost:3000/users にアクセスすると、以下のような画面が表示されるはずです。
表示が確認できたら次へ進みます。
(データ追加等は少しお待ちください)
セッション管理
ログイン機能を使う場合「ログインしているのは誰か?」を判断する必要があるので、セッション用ヘルパーモジュールを利用してこれを実装します。
コントローラー作成
コンテナ内で以下を実行します。
(モデルとビューは必要ないので、コントローラーのみを作成)
rails g controller Sessions new
実行すると、フォルダ内に app\controllers\sessions_controller.rb が作成されます。
sessions_controller.rb には new アクションのみなので、ログイン(create)とログアウト(destroy)のアクションを追加します。
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to root_url
else
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_url
end
end
- create・・・ログイン処理
- destroy・・・ログアウト処理
フォルダ内の config\routes.rb を開き、以下のように編集します。
(赤:削除、黄色:追加)
Rails.application.routes.draw do
root 'users#index'
get 'sessions/new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
(以下略)
ログイン画面作成
フォルダ内の app\views\sessions\new.html.erb を開き、以下のように編集します。
(元々ある2行は削除してください)
<h1>ログイン</h1>
<%= form_for(:session, url: login_path) do |f| %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Log in" %>
<% end %>
ログイン状況に応じて表示切り分け
ログインしている場合はユーザー一覧とログアウトボタンを表示、
ログインしていない場合はログイン画面へのリンクを表示するようにします。
フォルダ内の app\views\users\index.html.erb を _logged_in.html.erb にリネームします。
リネームした app\views\users\_logged_in.html.erb を開き、最後に以下を追加します。
<%= link_to "ログアウト", logout_path, method: :delete %>
次にフォルダ内の app\views\users に index.html.erb を作成し、以下のように編集します。
<% if logged_in? %>
<%= render 'users/logged_in' %>
<% else %>
<%= render 'users/not_logged_in' %>
<% end %>
同様にフォルダ内の app\views\users に _not_logged_in.html.erb を作成し、以下のように編集します。
<p>Railsサンプルアプリです。ログインしていません。</p>
<%= link_to "ログイン", login_path%>
セッション用ヘルパー作成
フォルダ内の app\helpers\sessions_helper.rb を開き、以下のように編集します。
module SessionsHelper
# 渡されたユーザーでログインする
def log_in(user)
session[:user_id] = user.id
end
# 現在ログイン中のユーザーを返す(いる場合)
def current_user
if session[:user_id]
# find だとユーザーがログインしていない場合に例外が発生するので find_by で検索
@current_user ||= User.find_by(id: session[:user_id])
end
end
#受け取ったユーザーがログイン中のユーザーと一致すれば true を返す
def current_user?(user)
user == current_user
end
# ユーザーがログインしていれば true、その他なら false を返す
def logged_in?
!current_user.nil?
end
# 現在のユーザーをログアウトする
def log_out
session.delete(:user_id)
@current_user = nil
end
end
セッション用ヘルパーの読み込み
セッション用ヘルパーを全てのページで使えるように ApplicationController で読み込みます。また、ログイン済みかの確認も行います。
フォルダ内の app\controllers\application_controller.rb を開き、以下のように編集します。
class ApplicationController < ActionController::Base
include SessionsHelper
private
# ログイン済みユーザーかどうか確認
def logged_in_user
unless logged_in?
redirect_to login_url
end
end
end
アクション前チェック
アクション前にログインされているかのチェックを行い、不正な処理が行われないようにします。
フォルダ内の app\controllers\users_controller.rb を開き、以下のように編集します。
class UsersController < ApplicationController
before_action :logged_in_user, only:[:edit, :update, :destroy]
(以下略)
パスワード暗号化対応
最後に暗号化したパスワードを扱えるようにしたり、パスワードを暗号化して保存するように実装します。
フォルダ内の app\models\user.rb を開き、以下のように編集します。
class User < ApplicationRecord
has_secure_password
end
フォルダ内の app\controllers\users_controller.rb を開き、以下のように編集します。
(黄色:変更)
class UsersController < ApplicationController
(中略)
# Only allow a list of trusted parameters through.
def user_params
#params.require(:user).permit(:name, :email, :password_digest)
params.require(:user).permit(:name, :email, :password, :password)
end
end
フォルダ内の app\views\users\_form.html.erb を開き、以下のように編集します。
(黄色:変更)
<%= form_with(model: user, local: true) do |form| %>
(中略)
<div class="field">
<%= form.label :password %>
<%= form.text_field :password %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
確認
それでは確認してみましょう。
まず、docker-compose up を行ったコマンドプロンプトで Ctrl + C を行い一度停止、
再度 docker-compose up を行って起動します。
起動したらブラウザで http://localhost:3000/users にアクセスしてみましょう。
以下のような画面が表示されるはずです。
「ログイン」をクリックしてみましょう。
ログイン画面が表示されるはずです。
ですが、ログインしようにもユーザーを登録していません。
最初のユーザーは手動で登録してみましょう。
ユーザー手動登録
scaffold を行った時の手順を参考に、コンテナに入り、以下を実行します。
rails c
プロンプトが「irb(main):001:0>」に変わったのを確認したら、以下を実行します。
User.create(name: "admin", email: "admin@test.com", password: "hogehoge", password_confirmation: "hogehoge")
登録できたら「exit」で抜けます。
再度ブラウザで http://localhost:3000/users にアクセスし、
Emailに「admin@test.com」、Passwordに「hogehoge」を入力し「Log in」してみましょう。
以下のように表示されるはずです。
・Password digest は暗号化されたパスワードです。
あとは好きにユーザーを作ったり消したりしてみてください。
終わりに
次回(最終回)は Bootstrap と Font Awesome を使って画面を装飾していきます。
- 当ページの人物画像はNIGAOE MAKERで作成しました。