草野球の出欠確認Webアプリを作ろう！　part.15

これから作っていく簡単なWebアプリの作成メモ（自分の備忘）です。
自分用なのであまり凝りすぎないように書いていきたい。

[<<前回の記事](https://qiita.com/tomodachi_uec/items/5d6181434bd241760eaa)

##今回やったこと

今回はユーザーがログインできるようにしたい。
以下の記事で詳細な説明をしていたのでぜひ紹介したい。
[【Rails】ログイン機能を実装する](https://qiita.com/d0ne1s/items/7c4d2be3f53e34a9dec7)

上記の記事を大いに参考にさせていただきます。

bcryptは導入済み、User.rbにも`hash_secure_password`を追加済みなので、セッションを利用したユーザー管理ができるようにする。
Sessionsコントローラーを作成する。

```bash
$ rails g controller Sessions new
```

ルーティングを作成しておく。

```rb:config/routes.rb
(略)
# Sessions
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
(略)
```

各種の処理と画面を作成する。
まずは画面寄りの部分。

```bash
$ touch ./app/views/sessions.new.html.erb
```

```erb:app/views/sessions.new.html.erb
<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 %>
```

```erb:app/views/layouts/_header.html.erb
(略)
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
  <% if logged_in? %>
    <a class="dropdown-item" href="<%= root_path %>">ホーム</a>
    <a class="dropdown-item" href="<%= schedules_path %>">予定</a>
    <a class="dropdown-item" href="<%= users_path %>">ユーザー</a>
    <a class="dropdown-item" href="<%= logout_path %>" data-method="delete">ログアウト</a>
  <% else %>
    <a class="dropdown-item" href="<%= login_path %>">ログイン</a>
  <% end %>
</div>
(略)
```

※aタグでdeleteのリクエストを送信するために`data-method`属性を設定しているが、以下の記事を参考にした。
[[Rails]aタグでも「data-method="delete"」を設定すればlink_toと同じ挙動](https://qiita.com/haruya_hamasaki/items/b69de2c680bb01d88017)
[link_toで突然methodが効かなくなって困ってるあなたへ](https://qiita.com/nilinomiya1222/items/e50b1dcc3da0da36988b)

次に内部処理寄りの部分。
まずはヘルパーから。

```rb:app/helpers/sessions_helper.rb
module SessionsHelper
 # 渡されたユーザーでログインする
  def log_in(user)
    session[:user_id] = user.id
  end

  # 現在ログイン中のユーザーを返す (いる場合)
  def current_user
    if session[:user_id]
      #@current_user = @current_user || User.find_by(id: session[:user_id])と同じ意味
      @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
```

次にコントローラーの処理。

```rb:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include SessionsHelper
end
```

```rb:app/controllers/sessions_controller.rb
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
```

また、ログインしていないユーザーをログインページにリダイレクトするアクションを作成。

```rb: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
```

`logged_in_user`をスケジュールとユーザーのコントローラーのbefore処理として記述。

```rb:app/controllers/schedules_controller.rb
class SchedulesController < ApplicationController
  before_action :logged_in_user
（略）
```

```rb:app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :logged_in_user
（略）
```

以上で参考記事をもとにしたログイン処理の追加が完了した。

あとは、ログイン画面がプロトなので（以下添付画像のような見た目）、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534558/0c0afb39-45d0-1504-c034-80654b33c4c0.png)

これを以下のように手を加えた。

```erb:app/views/sessions.new.html.erb
<h1>ログイン</h1>
<%= form_for(:session, url: login_path, html: {class: "form-signin"}) do |f| %>
  <div class="form-label-group my-3">
    <%= f.label :email %>
    <%= f.email_field :email, class: "form-control", placeholder: "Eメールアドレス" %>
  </div>
  <div class="form-label-group my-3">
    <%= f.label :password %>
    <%= f.password_field :password, class: "form-control", placeholder: "パスワード" %>
  </div>
  <div class="d-grid gap-2">
    <%= f.submit "ログイン", class: "btn btn-lg btn-primary my-3" %>
  </div>
<% end %>
```

こうすると、以下のようにログイン画面が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534558/bcddb665-1f40-5934-eb9d-c4f7372a8bcc.png)


結構進んだ。
まだログイン失敗時も含め、方々のエラーメッセージ表示ができないが、今回はここまで。

<!--
[次回の記事>>]()
-->