Ruby / Rails

ログイン機能を追加

2019年7月6日

こんにちは、Nanayakuです。

今回は、ログイン機能の追加について解説していきます。

目次

ログインの仕組み

HTTPは「ステートレス」と言う特徴があります。

これは、1つ1つの通信が独立しており、前回の通信の情報を記憶することが出来ないと言う事です。

これでは、ログイン状態を保持しているのは不可能です。

実装しようとすると、全てのリクエストでユーザー情報を入力する必要があります。

そこで、考えられたので「Cookie」と「Session」と言う技術です。

Cookieはユーザーのブラウザにテクストデータ(ユーザー固有の情報)を保存し、接続してから切断するまでログイン状態を保持できます。

ただし、ブラウザにテキストデータとして残すので、セキュリティの問題があります。

Sessionは、サーバー側に情報を保存し、暗号化してクライアント側にCookieとして保存する方法です。

Railsでは、このSessionを使用します。

 

Sessionの実装

Sessionを実装には、SessionのコントローラーとViewを作成します。

コントローラーの作成

rails g controller Sessions new」のコマンドでnewアクションを持ったSessionsディレクトリを作成します。

ルーターの設定

画像のようにルートを追記します。

get 'login', to: 'sessions#new'

getは所得するだけのメソッドなので、ログインのためのフォームへ転送します。

post 'login', to: 'sessions#create'

postは作成するメソッドなので、フォームで入力した情報を元にSessionを作成する処理の振り分けます。

delete 'logout', to: 'sessions#destroy'

deleteは削除するメソッドなので、Sessionを削除する処理に振り分けます。

まとめるとルーターは、「ログインフォームに移動」「Sessionの作成」「Sessionの削除」の役割のコントローラーに処理を振り分けています。

 

Viewの作成・編集

コントローラーを作成した時に、一緒に作成された「sessions/new.html.erb」にログインフォームを作成します。

form_for構文は以下のようになります。

<%= form_for :session, url: login_path do |f| %>

<% end %>

user(登録フォーム)の場合は以下のように、URLを@userで書けました。

<%= form_for @user do |f| %>

@userで出来たのは、入力されたデータを保存するUserモデルがあったため、Railsが自動的にcreateメソッドへアクセスしました。

しかし、今回はデータを保存するSessionモデルがないため、オプションでURLを指定しなければなりません。

Topページと登録フォームのログインのリンクを「login_path」にします。

 

コンローラーの設定

UsersControllerとSessionsControllerの違いと書くコードの解説をします。

Sessionはモデルを持たないため、インスタンス変数の@userに代入する必要がありません。

user = User.find_by(email: params[:session][:email])

これは、フォームから送信されたメールアドレスと一致するユーザーがいるか検索しています。

 

user.authenticate(params[:session][:password])

has_secure_passwordをUserモデルに追加したことで、そのオブジェクト内でauthenticateメソッドが使えるようになっています。このメソッドは、引数に与えられた文字列 (パスワード) をハッシュ化した値と、データベース内にあるpassword_digestカラムの値を比較します。

Ruby on Rails チュートリアル

つまり、authenticateメソッドはデータベースのパスワードとフォームから送信されたパスワードを比較し、trueかfalseを返します。

 

if user && user.authenticate(params[:session][:password])

上記の2つの条件を合わせ、「該当のメールアドレスをもつuserが存在し、かつuserのパスワードが正しい」と言う条件になります。

 

def log_in(user)

session[:user_id] = user.id

end

sessionメソッドは、sessionに暗号化した情報を保存するメソッドです。

log_inメソッドでsession[:user_id]にログイン情報を保存しています。

 

ナビゲーションの作成

ナビゲーションバーの作成とログイン画面へ遷移するリンクを作成します。

まずは、「app/helpers/application_helper.rb」と「app/controllers/application_controller.rb」に以下のコードを追記します。

def current_user

@current_user ||= User.find_by(id: session[:user_id])

end

def logged_in?

!current_user.nil?

end

||=」は、左辺が未定義または偽なら右辺の値を代入すると言う意味です。

これにより、「データベースの中のid」と「sessionに保存されているid」が一致したならば、@current_userにその情報を代入すると言う意味です。

つまり、current_userは、現在ログインしているuserを返すメソッドです。

  • application_helperなどのhelperはViewで共通で使用するコード
  • application_controllerはcontrollerで共通で使用するコード

をそれぞれ指定できます。

ログイン状態でであることを表示したい場合、application_helperとapplication_controllerの両方にメソッドを書きます。

「app/views/layouts/application.html.erb」と「app/assets/stylesheets/custom.scss」でナビゲーションバーのViewを作成します。

 

ログアウト機能の追加

ログアウトは、保存したsession情報を削除することでできます。

Sessionsコントローラーにdestroyアクションとlog_outメソッドを追記します。

画像の赤枠が追記した部分です。

「session.delete(:user_id)」でsessionの中にあるユーザー情報を削除します。

この時、インスタンス変数の@current_userの中には、ログインしているユーザー情報が残ったままなのでnilを代入します。

destroyアクションはユーザー情報を削除し、Topページに転送して「ログアウトしました」とフィードバックを表示する意味です。

 

Sessionsコントローラーにストロングパラメーターを実装

params.require(:session).permit(:email)

これは、フォームの情報のemailのみを生成することを意味しており、引数(:email)を渡すことで、フォームのemailのみ取得できる意味です。

passwardも同じです。

 

重複コードの対策

ApplicationControllerとApplicationHelperには同じコードが存在するため、どちらかを削除する必要があります。

エラーが出て動かなくなるわけではないのですが、Railsの設計思想に反しており、このまま開発を続けた場合支障をきたす可能性があります。

helper_methodメソッドは、コントローラで定義されたいくつかのメソッドを明示的に共有して、それらをビューで使用できるようにすることです。これは、コントローラとヘルパー/ビューの両方からアクセスする必要のあるメソッドで使用されます

ruby-on-rails – Railsでは、helperとhelper_methodの正確な動作は何ですか?

共通化したいメソッドが2つあるので以下のような書き方になります。

helper_method :current_user, :logged_in?

 

最後に

今回作ったアプリをgitにあげました。

良かったら見てみて下さい。

https://github.com/sabakan789/test.rails

備忘録がわりに作ったので、間違っている所とかあったら、コメントくれると嬉しいです。

-Ruby / Rails
-

© 2024 Nanayaku blog Powered by AFFINGER5