###### tags: `rails` `user` `bcrypt` `暗号化`
# railsでの会員登録 & ログイン
## Webアプリでの会員登録の重要性
まずこれからご説明させて頂く、会員登録機能に入る前に会員登録の重要性に関して十分にご注意頂ければと思います。
会員登録とはただ単にデータをデータベースに保存をするという認識で取り組むのではなく、<b>個人情報</b>を扱うという点に十分に留意しながら取り組んでいきましょう
そのため、以下では最低限パスワードを暗号化する点をご説明させて頂きます。
それ以外にも暗号化すべき個人情報はありますが、それ以外に関しては機会がありましたらご説明させて頂ければと思います。
ちなみに<b>*個人情報流出で大企業でも信用が失墜したケースあります*</b>ので、中規模や小規模のサービスを運営しているところなどはそれだけで吹き飛んでしまいますので、
一旦は<b><u>パスワードは最低限</u></b>覚えていただきたい課題です。
## 会員登録
### bcryptの有効化
```rails=
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'bcrypt', '~> 3.1.7' # 上記のコメントアウトを外す。
```
パスワードの暗号化を行うため、上記bcryptのコメントアウトを外す。
コメントアウトを外しただけではGemfileに記載した内容をインストールする事は出来ないので、忘れずに`bundle install`を行う。
### Userモデルへの追記
上記にてパスワード暗号化のための機能であるbcryptのインストールが完了したので、
その機能を使用して暗号化したパスワードを保存するためにUserモデルへ機能を使いますという宣言を行う。
```rails=
class User < ApplicationRecord
has_secure_password
end
```
宣言といってもものすごく簡単で、上記のように`has_secure_password`と言う一文を定義したモデルの中に記載すればOK。
### パスワードカラムの定義の仕方
#### 新規でモデルを定義する場合
```bash=
rails g model User name:string email:string password_digest:string
```
上記定義の場合、name, email, password_digestが文字列形式のカラムで定義されますよと言うマイグレーションファイルとUserモデルを作成してくれる。
※注意点として必ず**password_digest**カラムとして定義すること。
#### 既存のモデルに定義する場合
```bash=
rails g migration AddPasswordDigestToUsers password_digest:string
```
いつも行う通りのカラム追加でマイグレーションファイルを作成する。
カラム追加の方法が不明の方は[カラム追加](https://hackmd.io/@good1luck21/BJoMq_w1_#%E3%82%AB%E3%83%A9%E3%83%A0%E3%81%AE%E8%BF%BD%E5%8A%A0)を参考にして頂ければと思います。
ここでも重要な点として必ず**password_digest**カラムとして定義すること。
新規、既存ともにファイルを作成したら`rails db:migrate`を実行する。
## 暗号化され保存されるか確認
rails consoleで、暗号化され正常にテーブルに保存されることを確認する。
```rails=
# 例: Userテーブル カラム:name, email, password_digest 全部string
rails console
user = User.new(name: "test", email: "test@test.com", password: "123456", password_confirmation: "123456")
user.save
```
上記にて正常にUserテーブルに保存されることを確認する。
ポイントとしてはカラム名はpassword_digestとして作成しているが、実際に使用する際には`password`と`password_confirmation`としてカラム操作を行う。
## チェックリスト
- [ ] Gemfileでコメントアウトされているbcryptのコメントを取ったか
- [ ] コメント削除後 bundle install を行ったか
- [ ] modelへのパスワードの定義として `password_digest` としたか
- [ ] has_secure_passwordを使用したいモデルへ追記したか
- [ ] テーブルに入れる際`password`と`password_confirmation`で記載しているか
うまく保存できないなどに関しては上記に何かしらの不備がありますので、チェックをしてみましょう。
----------------
#### 会員登録に関してのTips
コントローラーとビューを使っての登録の仕方に関しては、通常の登録の仕方と変わりありませんので、
[rails アプリでの新規データ登録](https://hackmd.io/@good1luck21/HyU-55bk_)を参考にしてみてください。
---------------
## ログイン
### 一意のカラムデータでユーザーを検索する
#### view sessions/new.html.erbの例<a id="ex_html"></a>
```rails=
<h1>Log in</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(:session, url: user_login_path) do |f| %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<br/>
<%= f.submit "Log in", class: "btn btn-primary" %>
<% end %>
</div>
</div>
<br/>
```
上記htmlの通り、まず**一意のカラムデータ**で`User.find_by`を行いたいため、
上記の例ではemailカラムで検索して、パスワードで認証する例のhtmlとなります。
パスワードは皆様ベースとなるかと思いますが、**検索するカラムを何にするかが重要**になります。
名前などの場合は被ってしまう可能性があるため、**email**もしくは**ニックネーム**で検索するようにしましょう。
#### controller sessions_controller.rbの例
```rails=
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email])
if user && user.authenticate(params[:session][:password])
session[:user_id] = user.id
redirect_to root_path
else
render :new
end
end
end
```
sessions/new.html.erbにてログインボタン押下後、コントローラーにパラメータが飛んできますので、
パラメータを取得して、認証するまでの流れを行っています。
[view sessions/new.html.erbの例](#ex_html)でもご説明しておりますが、**ポイントとしては一意の値で検索をするというところになります。**
ただしくfind_byで値を取得できれば、後は`authenticate`メソッドで認証をしてあげれば、パスワードが正しければsessionという半永続的に保持される変数にログインしたという意味合いで値を格納してあげれば完成です。
------------------
## ログインに関してのTips
うまくログインが出来ないという方がいらっしゃいますが、ログイン機能自体は複雑なことは何もしていません。
一意の値でカラムを検索できているのか、パラメータを正しく取得できているのかを確認してみましょう。
### カラム検索の例
```bash=
rails console
user = User.find_by(email: "test@test.com")
# ここで何も取得出来なければ正しいアドレスで検索できていません。
user = User.find_by(name: "test")
# 複数個取れてしまう場合はエラーが出るかと思いますので、一意のカラムで検索するようにしましょう
```
### パラメータ確認の例
```rails=
class SessionsController < ApplicationController
.
..省略
...
def create
p "==================="
p params
p "==================="
user = User.find_by(email: params[:session][:email])
if user && user.authenticate(params[:session][:password])
session[:user_id] = user.id
redirect_to root_path
else
render :new
end
end
end
```
上記のように`p "==================="`の中にparamsを出力しております。
こうすることで、rails server実行中のターミナルにパラメータの中身が出てきますので、find_byの部分で指定しているパラメータ取得の仕方が正しいのかの検証を行いましょう。
----------------
以上、会員登録とログインに関してでした。
一見複雑そうですが、基本流れは一緒なので、一度やれば覚えてしまうかなと思いますので、
チャレンジしてみましょう!