新規登録、ログイン、ログアウトなどを実装するために
ユーザー管理機能を追加していきます。
##deviceというGemを利用します。
Gemfileの最後にdeviceを追加記述しましょう。
gem 'devise'
Gemをインストールしましょう。
% bundle install
Gemを導入した際にはサーバーの再起動が必要です。
% rails s
##rails g devise:installコマンド
追加したdeviseというGemの「設定関連に使用するファイル」を自動で生成するコマンドです。
% rails g devise:install
##rails g deviseコマンド
deviseによるユーザー機能の対象を指定することで、
モデルとマイグレーションの生成やルーティングの設定などをまとめて処理します。
ルーティングにはdeviseに関連するパスが追加されます。
# deviseコマンドでUserモデルを作成
% rails g devise user
ルーティングを確認してみましょう。
Rails.application.routes.draw do
devise_for :users
root to: 'tweets#index'
resources :tweets
end
devise_forは、ユーザー機能に必要な複数のルーティングを
まとめて生成してくれるdeviseのメソッドです。
マイグレーションファイルを確認してみましょう。
class DeviseCreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
# 省略
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
Eメールやパスワードなどの設定が確認できますね。
##マイグレーションを実行します。
# マイグレーションを実行
% rails db:migrate
テーブル・カラム情報を変更したため、ローカルサーバーを再起動してください。
% rails s
##deviseのビューファイルを作成
ビューファイルは自動で生成されないのでコマンドを実行する必要があります。
deviseのGem内に存在するビューファイルを読み込んでいるためです。
##rails g devise:viewsコマンド
% rails g devise:views
このコマンドでビューファイルを生成することができます。
サインアップ画面はapp/views/devise/registrations/new.html.erb
ログイン画面のビューはapp/views/devise/sessions/new.html.erb
というビューファイルが対応しています。
装飾したい場合はこのビューを変更します。(今回は最低限行います)
<h2 class="contents" >新規登録</h2>
<div class="center">
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="actions">
<%= f.submit "新規登録する" %>
</div>
<% end %>
</div>
<h2 class="contents" >ログイン</h2>
<div class="center">
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "current-password" %>
</div>
<div class="actions">
<%= f.submit "ログインする" %>
</div>
<% end %>
</div>
cssも当て直します。
.btn,
.post {
padding: 8px 20px;
font-size: 14px;
border: 2px solid #57C3E9;
color: #57C3E9;
font-weight: bold;
text-align: center;
border-radius: 3px;
display: inline-block;
margin: 5px;
}
.btn:hover,
.post:hover {
border-color: #9bdbf2;
color: #9bdbf2;
}
footer {
margin: 30px auto;
padding: 10px;
color: #D8D8D8;
text-align: center;
}
header {
margin: 30px auto;
padding: 10px;
color: #D8D8D8;
text-align: center;
}
.content_post {
text-align: center;
}
.container_box {
text-align: center;
}
.container {
margin: auto;
display: block;
}
.contents {
text-align: center;
}
.top_contents {
display: flex;
justify-content: center;
}
.center {
width: 100vw;
display: flex;
justify-content: center;
}
以下にアクセスするとログイン画面が確認できます。
http://localhost:3000/users/sign_in
以下にアクセスするとサインアップ画面が確認できます。
サインアップ時に登録する情報はメールアドレスとパスワードの2つですが
加えてニックネームを登録できるようにしましょう。
テーブルにカラムを追加するために、マイグレーションを生成します。
以下のコマンドを実行します。
##rails g migrationコマンド
rails g migration Addカラム名To追加先テーブル名 追加するカラム名:型
必要なコードが記述された状態で、マイグレーションが生成されます。
ファイル名やクラス名などに使用される表記方法のルールをみてみましょう。
表記方法 | 説明 | 例 |
---|---|---|
キャメルケース | 先頭が小文字で、単語の区切りを大文字で表す | adminUserCommentCreator |
アッパーキャメルケース | キャメルケースの1つ。先頭から単語の区切りを大文字で表す(クラス名) | AdminUserCommentCreator |
スネークケース | 単語の区切りをアンダースコアで表す(メソッド名、変数名) | admin_user_comment_creator |
##usersテーブルにnicknameカラムをstring型で追加
# usersテーブルにnicknameカラムをstring型で追加するマイグレーションファイルを作成
% rails g migration AddNicknameToUsers nickname:string
# 作成したマイグレーションを実行
% rails db:migrate
テーブル・カラム情報を変更したため、ローカルサーバーを再起動してください。
% rails s
次はニックネーム情報をフォームから登録できるようにビューを編集します。
今回は、ニックネームを6文字以内で登録させるようにします。
###maxlengthオプション
maxlengthオプションは、inputタグを生成するヘルパーメソッドである、 text_fieldにつけることができるオプションです。入力できる最大文字数を指定できます。
#maxlengthオプションの一例
<div class="field">
<%= f.text_field :nickname, autofocus: true, maxlength: "6" %>
</div>
<h2 class="contents" >新規登録</h2>
<div class="center">
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :nickname %> <em>(6 characters maximum)</em><br />
<%= f.text_field :nickname, autofocus: true, maxlength: "6" %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="actions">
<%= f.submit "新規登録する" %>
</div>
<% end %>
</div>
##ストロングパラメーターの設定
deviseに関しても、他と同様にストロングパラメーターをコントローラーに記述したいところです。
しかし、deviseの処理を行うコントローラーはGem内に記述されているため、編集することができません。
##devise_parameter_sanitizerメソッド
deviseにおけるparamsのようなメソッドで、deviseのUserモデルに関わる「ログイン」「新規登録」などのリクエストからパラメーターを取得できます。
このメソッドとpermitメソッドを組み合わせることで、deviseに定義されているストロングパラメーターに対し、新しく追加したカラムも指定して含めることができます。
これまでのストロングパラメーターと同じく、新たに定義するプライベートメソッドの中で使用します。deviseの提供元では、新たに定義するメソッド名をconfigure_permitted_parametersと紹介していることから、慣習的にこのメソッド名で定義することが多いようです。
private
def configure_permitted_parameters # メソッド名は慣習
# deviseのUserモデルにパラメーターを許可
devise_parameter_sanitizer.permit(:deviseの処理名, keys: [:許可するキー])
end
devise_parameter_sanitizerに使用するpermitメソッドの引数の指定の仕方は異なります。
# paramsのpermitメソッド
params.require(:モデル名).permit(:許可するキー)
# devise_parameter_sanitizerのpermitメソッド
devise_parameter_sanitizer.permit(:deviseの処理名, keys: [:許可するキー])
deviseのpermitは、第一引数にdeviseの処理名、第二引数にkeysというキーに対し、配列でキーを指定することで、許可するパラメーターを追加していきます。
第一引数の処理名には、deviseで設定されているsign_in, sign_up, account_update
が使用でき、それぞれの処理に対応しています。
第一引数で指定した処理に対して、第二引数のkeysで指定された名前と同じキーを持つパラメーターの取得を許可します。ビューに記述した各フォーム部品のname属性値が、フォームから送信されるパラメーターのキーになります。
deviseにストロングパラメーターを追加するコードは、deviseのコントローラーが編集できないため、application_controller.rbに記述していきます。
##application_controller.rbを編集
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
private
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
end
end
:devise_controller?というdeviseのヘルパーメソッド名を指定して、deviseに関するコントローラーの処理のときだけメソッドを実行するように設定しています。
ビューを整えていきましょう。
ログインしているときはログアウトと新規投稿のボタンを表示
ログインしていないときはログインと新規登録のボタンを表示します。
##user_signed_in?メソッド
ユーザーがログインしていればtrueを、ログアウト状態であればfalseを返します。
# ログインしているユーザーのとき
user_signed_in?
#=> true
# ログインしていないユーザーのとき
user_signed_in?
#=> false
<!DOCTYPE html>
<html>
<head>
<title>Tsubuyaki</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<header class="header">
<div class="header__bar row">
<h1 class="grid-6"><a href="/">Tsubuyaki</a></h1>
<div class="top_contents">
<div class="user_nav grid-6">
<% if user_signed_in? %>
<div class="user_nav grid-6">
<%= link_to "ログアウト", destroy_user_session_path, method: :delete,class: "post" %>
<%= link_to "投稿する", new_tweet_path, class: "post" %>
</div>
<% else %>
<div class="grid-6">
<%= link_to "ログイン", new_user_session_path, class: "post" %>
<%= link_to "新規登録", new_user_registration_path, class: "post" %>
</div>
<% end %>
</div>
</div>
</header>
<%= yield %>
<footer>
<p>
Copyright Tsubuyaki 2021.
</p>
</footer>
</body>
</html>
しかしこのままだと問題があります。
ログインしていなくてもURLを直接入力してしまうと新規投稿パスに行けてしまうのです。
対策をしていきましょう。
##unless
ifと同様に、条件式の返り値で条件分岐して処理を実行するRubyの構文です。
ifは返り値がtrueのときにelseまでの処理が実行されますが、
unlessはfalseのときにelseまでの処理が実行されます。
redirect_toメソッド
Railsでリクエストと違うページに返すリダイレクト処理を行う際に使用するメソッドです。
コントローラー等での処理が終わった後、アクションに対応するビューファイルを参照せずに、別ページへリダイレクトさせることができます。
redirect_to action: :リダイレクト先となるアクション名
###exceptオプション
before_actionで使用できるオプションです。exceptは「除外する」という意味がありこの中に記述したアクションには処理が適用されません。
class TweetsController < ApplicationController
before_action :set_tweet, only: [:edit, :show]
before_action :move_to_index, except: [:index, :show]
def index
@tweets = Tweet.all
end
def new
@tweet = Tweet.new
end
def create
Tweet.create(tweet_params)
end
def destroy
tweet = Tweet.find(params[:id])
tweet.destroy
end
def edit
end
def update
tweet = Tweet.find(params[:id])
tweet.update(tweet_params)
end
def show
end
private
def tweet_params
params.require(:tweet).permit(:name, :image, :text)
end
def set_tweet
@tweet = Tweet.find(params[:id])
end
def move_to_index
unless user_signed_in?
redirect_to action: :index
end
end
end
以上で終了です。以下の挙動になっていれば成功です。
##新規登録
今回は以上です。