こんにちは! フリーエンジニアの長瀬です。
みなさんはセッションを使っていますか?
セッションはログイン機能を実装するには必須のもので、ログインに成功した後にログイン状態を維持するために使用されます。
この記事では、セッションの使い方について
・ セッションとは
でセッションの役割について解説した後
・セッションを使ってみよう
で実際にRails5でセッションの使い方をわかりやすいサンプルコードとともに学んでいきましょう。
セッションとは
セッションは主にログイン機能に使用されるもので、ログイン状態を持続させるためにあります。
セッションのおかげで、一度ログインした後は登録されたユーザーとしての扱いを受けることができます。
逆に、セッションという仕組みがなければページを移動するたびにログインし直さなければならないことになるので、とても不便です。
ログイン機能の実装には必要なのでRailsでは、あらかじめセッションを実装するために便利なメソッドが用意されていて、簡単に実装することができます。
また、セッションの情報はRails標準では、ブラウザ側のクッキーに保存されるということも覚えておいてください。
セッションを使ってみよう
それでは、実際にセッションの仕組みを使って簡単なログイン機能を実装してみましょう。
実行環境はrails5.1.4で進めていきます。
今回はセッションに焦点を当てて説明しますので、ユーザーを登録する画面は作成しません。
あらかじめご了承ください。
まずは、ユーザーを登録するためのユーザーモデルを作成します。
ユーザーモデルには、名前とパスワードが登録できるようにします。
始めに、パスワードを暗号化するためのgemを追加します。
Gemfileに以下の行をコメントインしてください。
# gem 'bcrypt', '~> 3.1.7'
↓
gem 'bcrypt', '~> 3.1.7'
bcryptというgemを使えば、データベースにパスワードを保存する際に、暗号化してくれます。
コメントインが完了したら、コマンドプロンプトで
bundle install
と入力して、gemのインストールを完了してください。
それでは次にgenerateコマンドを使って、Userモデルを作成します。
コマンドプロンプトに以下のコマンドを入力してください。
rails generate model User name:string password_digest:string
実行結果
Running via Spring preloader in process 95595 invoke active_record create db/migrate/20170919084828_create_users.rb create app/models/user.rb
password_digestというカラムには暗号化されたパスワードが入ります。
password_digestはbcryptの仕様ですが、このカラム名にするとパスワードが暗号化されて保存されるようになります。
migrationファイルが作成されたので、以下のコマンドを入力してデータベースに反映してください。
rails db:migrate
実行結果
== 20170919084828 CreateUsers: migrating ====================================== -- create_table(:users) -> 0.0009s == 20170919084828 CreateUsers: migrated (0.0009s) =============================
これでユーザーモデルの作成は完了です。
次に、作成したapp/models/user.rbにパスワードの暗号化を有効にするための設定を加えます。
[app/models/user.rb]
has_secure_password
次に、実際にユーザーを登録します。
この登録されたユーザー情報を使って、ログインを実装するためです。
rails cでコンソールを開いた後に、以下のコードを入力してください。
User.create(name:"samurai",password: "test",password_confirmation: "test")
実行結果
(0.1ms) begin transaction SQL (0.9ms) INSERT INTO "users" ("name", "password_digest", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "samurai"], ["password_digest", "$2a$10$tef8qdFI9B9DeoyrJ/lwiOq5H0ci3mRM37S0xYxL8.9xnUrjPQ/TS"], ["created_at", "2017-09-19 09:06:22.436845"], ["updated_at", "2017-09-19 09:06:22.436845"]] (0.9ms) commit transaction +----+---------+--------------------------------------------------------------+-------------------------+-------------------------+ | id | name | password_digest | created_at | updated_at | +----+---------+--------------------------------------------------------------+-------------------------+-------------------------+ | 1 | samurai | $2a$10$tef8qdFI9B9DeoyrJ/lwiOq5H0ci3mRM37S0xYxL8.9xnUrjPQ/TS | 2017-09-19 09:06:22 UTC | 2017-09-19 09:06:22 UTC | +----+---------+--------------------------------------------------------------+-------------------------+-------------------------+ 1 row in set
コンソールには表形式で表示されるようにHirbというgemを使用しています。
まだ、設定したことのない方はこちらの記事を参考にしてください。
それでは、ユーザーも登録できたので、ログイン画面を作成していきましょう。
generateコマンドを使って、一気に必要なファイルを作成します。
コマンドプロントに以下のコードを入力してください。
rails generate controller sessions index
実行結果
Running via Spring preloader in process 96983 create app/controllers/sessions_controller.rb route get 'sessions/index' invoke erb create app/views/sessions create app/views/sessions/index.html.erb invoke helper create app/helpers/sessions_helper.rb invoke assets invoke coffee create app/assets/javascripts/sessions.coffee invoke scss create app/assets/stylesheets/sessions.scss
では、必要なファイルは揃ったので、まずはコントローラーからコードを入力していきましょう。
app/controllers/sessions_controller.rbを開いて、以下のようにコードを修正してください。
class SessionsController < ApplicationController def index if session[:user_name] @notice = "#{session[:user_name]}でログインしています。" end if params.key?(:name) || params.key?(:password) user = User.find_by_name(params[:name]) if user && user.authenticate(params[:password]) session[:user_name] = params[:name] else session[:user_name] = nil end end end end
何が書いてあるかを理解するために、コードの解説をします。
まず、
if params.key?(:name) || params.key?(:password) user = User.find_by_name(params[:name]) if user && user.authenticate(params[:password]) session[:user_name] = params[:name] else session[:user_name] = nil end end
の部分で、ログインボタンを押した後に、セッションに情報が保存されるかを判断しています。
user = User.find_by_name(params[:name])
params[:name]で、ユーザーがポストした値を取り出し、その後find_by_nameメソッドで、入力したnameとカラムに保存されたnameが一致した場合にユーザーに代入しています。
今回はレコードは登録した1つしかないので、コンソール出力されたものが代入されます。
次に、
if user && user.authenticate(params[:password])
では&&を使って、条件を2つ指定しています。
userで、userの中身があるのかどうかを判断し、user.authenticateでは今回userに代入されたレコードのパスワードがユーザーがポストした値と一致しているのか判断しています。
もしも、パスワードが一致していなかったら、falseを返します。
そして、パスワードが登録されたユーザー情報と一致したら
session[:user_name] = params[:name]
で、セッションにユーザー名を登録しています。
session[:名前] はRailsにあらかじめ組み込まれているメソッドで、名前をつけて、セッションに登録できます。
たったこれだけのメソッドで、簡単にセッションの設定ができます。
また、else以降
session[:user_name] = nil
でセッションを破棄しています。
そしてここまで説明すれば、前半の
def index if session[:user_name] @notice = "#{session[:user_name]}でログインしています。" end
の部分のコードを説明できます。
この部分では
session[:user_name]
で、ログインされているかを判断して、ログインされていたらインスタンス変数noticeを定義しています。
それでは、次にログイン画面を作成していきましょう。
先ほど作成されたapp/views/sessions/index.html.erbを開いて以下のように修正してください。
<h1>簡易ログイン画面</h1> <%= form_with url: sessions_index_path %> 名前:<%= text_field_tag :name %> パスワード:<%= password_field_tag :password %> <%= submit_tag 'ログイン' %> <%= @notice %>
form_withメソッドで、入力フォームを作成しています。
また、sessions_index_pathでポスト先を指定してるので、ポスト用のルーティングを指定してあげる必要があります。
なのでconfig/routes.rbを開いて,以下のようにルーティングを修正してください。
Rails.application.routes.draw do get 'sessions/index' post 'sessions/index' end
これで、コントローラーとビューの設定が完了しました。
では、実際にログインして、セッションがうまく機能している確認しましょう。
コマンドプロンプトにrails sと入力して、サーバーを起動してください。
そして、ルーティングに従って、
http://localhost:3000/sessions/index(補足http://localhost:3000の箇所は各自の開発環境により読み替えてください。)
にアクセスしてください。
ここにさきほど登録したnameとpasswordを入力してください。
(nameはsamuraiで、passwordはtestです)
ログインボタンを押すとコントローラーのところで説明したコードに従って、セッション情報が登録されます。
ログインが成功していたら、ページを更新すると
このように、@noticeに定義した値が出力されます。
@noticeにはセッション情報が使用されているので、セッションが成功していることを確認できました。
まとめ
いかがでしたでしょうか?
この記事では、セッションの使い方を解説しました。
ログイン機能を実装するにはセッションの扱い方を知っておく必要があります。
またRails標準ではブラウザ側のクッキーにセッションの情報は保存されますが、保存先を変更することもできるので興味があるかたは調べてみてください。
もしセッションの使い方について忘れてしまったらこの記事を確認してくださいね!