はじめに
WEBサイトを作成する上で、ユーザーの登録からログイン・ログアウトまでできるサイトがほとんどだと思います。今回は、deviseを使って実装していきましょう。
目次
- サーバーが起動していたら停止する
- Gem(devise)をインストールする
- deviseの設定ファイルを作成する
- Userモデルを作成する
- 必要なビューの知識
- パスの調べ方(prefix)
- サインイン(user_signed_in?)
- リダイレクトをコントローラーに実装する
- 新規登録・ログイン画面を実装する(view)
- usersテーブルに名前を保存できるようにする
- 命名規則(スネークケース・キャメルケース)
- 新規登録画面に名前フォームを追加する
- ストロングパラメータを編集する(devise用)
サーバーが起動していたら停止する
control + Cキー を同時押ししましょう。
Gem(devise)をインストールする
まずはじめにGemfileに以下を追記しましょう。
gem 'devise'
続いて bundle install を実行します。
$ bundle install
deviseの設定ファイルを作成する
$ rails g devise:install
deviseに必要な2つのファイルが生成されました。
create config/initializers/devise.rb
create config/locales/devise.en.yml
ユーザーを登録するためには、何が必要でしょうか?そうですアカウントを保存するためのデータベースが必要ですね。まずは、モデルを作っていきましょう。
Userモデルを作成する
ここで注意しなければいけないのがdevise専用のコマンドを実行することです。
以下を実行してUserモデルを生成します。
$ rails g devise user
必要なファイルが生成されました。
モデルを生成しただけでは、テーブルは作成されていませんね。
以下のコマンドを実行してテーブルを作成しましょう。
$ rake db:migrate
これでテーブルができました。
必要なビューの知識
ここで、少しビューの知識についても触れておきます。なぜならログイン機能は、ログインされている時とログアウトしている時のナビゲーションの表示が異なる場合がほとんどだからです。
表示タグ(<% %>)
<% post.text %>
ビューに表示されない
<%= post.text %>
ビューに表示される
リンク(link_to)
HTMLだとaタグと同様だと思ってください。html.erbファイルでは、以下のように記述します。
<%= link_to 'ビューに表示される文字', 'パス' %>
クラスをつける場合は以下のようになります。
<%= link_to 'ビューに表示される文字', 'パス', class: 'クラス名' %>
パスの調べ方(prefix)
Railsでは、パスをターミナルで調べる方法があります。
$ rake routes
実行後
posts_new GET /posts/new(.:format) posts#new
現在、使えるパスがズラーッと表示されたかと思いますが、
posts_new
これが、リンクタグなどで使えるパスになります。ただ、これを追記するだけではエラーになってしまいます。例えば、新規投稿画面へのリンクをブラウザに表示する場合には以下を参考にしてください。
<%= link_to '新規投稿画面へ移動します', 'posts_new_path' %>
このように調べたパスのあとに _path とつけるだけです。
サインイン(user_signed_in?)
ログイン・ログアウト機能で必要なメソッドになります。使い方は簡単です。
<% if user_signed_in? %>
# ユーザーがサインインしている場合に実行する処理
<% end %>
サインアウトしている場合は、なにを追記すればいいでしょうか?ヒントは条件分岐です。
<% if user_signed_in? %>
# ユーザーがログインしている場合に実行する処理
<% else %>
# ユーザーがログアウトしている場合に実行する処理
<% end %>
ログイン・ログアウトの機能は全てのページに表示させておく必要があるので、共通のビューに関する記述は app/views/layouts/application.html.erb でしたね。
<header class="header">
<div class="header__bar row">
<h1 class="grid-6"><a href="/">サイトタイトル</a></h1>
<% if user_signed_in? %>
<div class="user_nav grid-6">
<%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
<a class="post" href="/posts/new">投稿する</a>
</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>
</header>
上記は、あくまで参考ですので、レイアウトは変更してください。これで、ナビゲーションにログイン・ログアウトのリンクをつけることができました。
リダイレクトをコントローラーに実装する
ログイン・ログアウト機能まで実装することができました。ただ、一つ問題点があります。それは、新規投稿のパスに直接アクセスできてしまいます。それができないようにログインしてない場合には強制的にログイン画面に移動するようにリダイレクトという機能を実装していきます。
リダイレクトする(redirect_to)
Railsでは、アクション内の処理が終了すると"自動的"にアクション名と同名のビューが表示されますので、アクションの処理が終わり強制的に別のアクションを実行する場合などに使います。
redirect_to action: :index
キー: :バリュー
※indexアクションにリダイレクトするという記述になります。
指定のアクションを優先して実行する(before_action)
before_action :manji, except: :index
# indexアクション以外が実行される前にmanjiメソッドが実行される。
def index
@posts = Post.all
end
private
def manji
end
それでは、ログインしていないときに新規投稿しようとすると、indexアクションに強制リダイレクトするようにmanjiアクションに記述していきます。
private
def manji
redirect_to action: :index unless user_signed_in?
end
unlessという見慣れないコードがでてきました。
unless文
簡単にいうとif文と真逆の処理をします。
if文は もしも評価が真(true)であれば○○する でしたね。
unless文は もしも評価が偽(false)であれば○○する という意味になります。
unless 条件式
# 条件式が偽(false)のときに実行する処理
else
# 条件式が真(true)のときに実行する処理
end
それでは、コントローラーを以下に編集します。
class PostsController < ApplicationController
before_action :manji, except: :index
def index
@posts = Post.page(params[:page]).per(5).order("created_at DESC")
end
def new
end
def create
post.create(post_params)
end
private
def post_params
params.permit(:name, :text)
end
def manji
redirect_to action: :index unless user_signed_in?
end
end
これで、ログイン前に新規投稿ができるという問題が解決しました。
ログイン・新規登録画面を実装する(view)
deviseでログイン機能を実装すると、ログイン・新規登録画面は自動的に生成されますがビューファイルとしては生成されていません。ブラウザで、新規登録・ログインに進むと表示されますがこれはGem(devise)中のビューを読みこんでいるためです。
そこで、ログイン・新規登録画面のビューを変更するには以下のコマンドで、devise用のviewファイルを生成する必要があります。
$ rails g devise:views
実行すると app/views/devise にファイルが生成されました。
新規登録画面のviewを変更する
registrationsとは英語という意味になります。翻訳するとなんとなくパスも理解できると思います。
<div class="contents row">
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :password %>
<% if @validatable %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
</div>
ログイン画面のviewを変更する
<div class="contents row">
<h2>Log in</h2>
<%= 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 %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<% if devise_mapping.rememberable? -%>
<div class="field">
<%= f.label :remember_me %><br />
<%= f.check_box :remember_me %>
</div>
<% end -%>
<div class="actions">
<%= f.submit "Log in" %>
</div>
<% end %>
</div>
CSSやbootstrapのレイアウトについては、割愛しております。
ブラウザでログイン・新規登録画面を確認する
これで、ユーザー登録・ログインの準備ができました。今回は、登録するユーザーの名前も保存するようにします。ではここで、データの保存先(usersテーブル)確認してみます。
usersテーブルには「idカラム」「emailカラム」「passwordカラム」しか存在していないので、名前にあたる「nameカラム」を追加していきましょう。
usersテーブルに名前を保存できるようにカラムを追加する
名前を追加するためにusersテーブルにnameカラムを追加していきましょう。ここには、新規登録の時に登録する名前を保存できるようにします。
マイグレーションファイルを作成してカラムを追加する
ファイルを生成するコマンドは "rails g" でしたね。
$ rails g migration AddNameToUsers name:string
解説
$ rails g migration AddカラムToテーブル カラム:データの型
以下のコマンドを実行してテーブルを生成します。
$ rake db:migrate
これで、usersテーブルにnameカラムを追加することができました。
もし間違ったカラム名で追加してしまった場合などは一つ前に戻るコマンドを実行しましょう。
$ rake db:rollback
を実行したあとできてしまったマイグレーションファイルを消しましょう。
migrationファイルがどのような状態なのか確認するコマンド
$ rake db:migrate:status
Status Migration ID Migration Name
--------------------------------------------------
up 20190420082207 Create tweets
down 20190421185018 Devise create users
upなら実行されていてdownは未実行という意味
マイグレーションカラムの追加(add_column)
まず、マイグレーションファイルの生成をします。
$ rails g migration AddRateToテーブル名
マイグレーションファイルに追記します。
class AddPriceToBooks < ActiveRecord::Migration[5.2]
def change
add_column :テーブル, :カラム, :型
add_column :テーブル, :カラム, :型
end
end
マイグレーションカラムの削除(remove_column)
remove_column :テーブル名, :カラム名, :カラムの型
命名規則
先程、マイグレーションファイルを生成する時にターミナルに記述した命名規則2つを紹介します。
キャメルケース
単語の頭文字を大文字で繋げる
AddNameToUsers name:string
スネークケース
_で区切る
add_name_to_users name:string
新規登録画面に名前フォームを追加する
<div class="contents row">
<h2>Sign up</h2>
<%= 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 :name %> <em>(6 characters maximum)</em><br />
<%= f.text_field :name, autofocus: true, maxlength: "8" %>
</div>
<!-- ここまでを追記します -->
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :password %>
<% if @validatable %>
<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 "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
</div>
登録フォームに名前を登録するフォームが表示できました。
ストロングパラメータを編集する(devise用)
新規登録時に入力された情報はパラメーターとしてサーバーに送信されます。
ただ、deviseにはコントローラーが存在しないためapplication_controller.rbにdevise