hiyoko-programingの日記

プログラミングを勉強したてのひよっ子。   エンジニア目指して勉強中。

ユーザー管理実装

ユーザー管理実装のステップ

ユーザー管理機能を以下のステップで実装する。

  1. deviseのインストール
  2. Userモデルを作成する
  3. deviseのビューファイルの追加
  4. サインアップ機能の追加
  5. ユーザー情報編集機能の追加
  6. ログアウト機能の追加
  7. フラッシュメッセージの表示機能の実装

1. deviseのインストール

ユーザー管理機能を実装に、「devise」を使用する。
最初にインストールを行う。

 Gemfileに追加

Gemをインストールするため、Gemfileに追記。
下記の説明を参考に、記述する場所に注意。

Gemfile
1
2
3
(前略)
gem 'devise'
(後略)

以下のように、group内に記述すると特定の環境でのみ使用する設定になってしまう。deviseは開発、テスト、本番いずれの環境でも使用するので注意。

NG例

Gemfile
1
2
3
group :development do
  gem 'devise'
end

この記述だとdevelopment環境から、テストや本番環境に移行していくので、その際に対応できなくなってしまう。

 deviseのインストールを行う

続いてGemおよびdeviseのインストールを行う。deviseの場合は、bundle installの他にdevise用のインストールコマンドの実行が必要なので注意。

ターミナル
1
2
$ bundle install
$ rails g devise:install

2. Userモデルを作成

ユーザーを管理するためのモデルファイルや、テーブルを作成する。

以下の点に注意して、実装する。

・deviseで使用するモデルを作成するときは、rails g modelのような通常のモデル作成とはコマンドが異なる。

・どのようなカラムを追加するか、カラムにどのような制約をかけるか事前にDB設計を確認。

 

 問題1:devise用のUserモデルを作成。追加するカラムに気をつけ、マイグレートまで行う

 
ターミナル
1
$ rails g devise user
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class DeviseCreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :name,               null: false
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
    end
    add_index :users, :name, unique: true

# 〜省略〜
/models/user.rb
1
2
3
4
5
6
7
8
9
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable,  :validatable

  validates :name, presence: true

end

解説

deviseで使用するモデルは、rails g devise <モデル名>コマンドで作成できる。

ターミナル上でrails g devise Userを実行し、Userモデルを作成。

作成されたマイグレーションファイルを開き、t.string :name, null: false と add_index :users, :name, unique: trueを上記の様に追記。これで、マイグレーション実行時にnameカラムがNOT NULL制約・一意性制約付きで作成される。

NOT NULL制約では空の文字列は保存可能なため、validatesを使用。
更にuser.rb に validates :name, presence: trueと追記し、空の文字列の場合もエラーが発生する様にする。

最後にマイグレーションを実行。

ターミナル
1
$ rails db:migrate

コマンドを誤った場合の対応方法

誤ったコマンドを実行してしまった場合は、以下を参考に修正を行う。

rails gコマンドの誤り

rails g model userコマンドでファイルを作ってしまった場合は、下記のコマンドを実行してファイルの削除を行う。

ターミナル
1
rails d model user

マイグレーションファイルの誤り

マイグレーションファイルの記述を誤ったままマイグレートしてしまった場合は、下記のコマンドを実行してからもう一度やり直し。

ターミナル
1
rails db:rollback

 

3. deviseのビューファイルの設定

deviese用のスタイリングを行う。

 問題2:ファイルを配置する

①「devise」および「users」フォルダをapp/viewsフォルダに配置する。

②「user.scss」のファイルをapp/assets/stylesheets/modulesに配置する。

③下記のファイルを変更する。

app/assets/stylesheets/application.scss
1
2
3
4
5
@import "reset";
@import "modules/messages";
@import "font-awesome-sprockets";
@import "font-awesome";
@import "modules/user";

解説

ファイルが読み込まれるようapplication.scssにimport文を追加。

 

4. サインアップ機能の追加

deviseのデフォルトの機能では、「メールアドレス」および「パスワード」を入力してユーザー登録を行う。ChatSpaceでは「名前」も合わせてサインアップする仕様となっている。

ユーザー登録フォームのビューは、すでにダウンロードしたファイルであれば実装済み。そのほか、保存に必要な機能を実装する。

 application_controller.rbを編集

サインアップ時に、ユーザーの名前を登録できるようapplication_controller.rbを編集。

application_controller.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  before_action :authenticate_user!
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end

Railsでは、悪意のあるユーザーの入力に対してセキュリティ対策を行わないと保存できない仕組みがある。

通常のテーブルに保存する際はストロングパラメータを使用したが、deviseを使ったモデルの場合は方法が異なる。

上のコードは、deviseの公式サイトで紹介されている書き方。そのまま使用するものという理解でも問題ない。

application_controller.rb
4
before_action :configure_permitted_parameters, if: :devise_controller?

application_controllerにbefore_actionを使用しているため、全てのアクションが実行される前に、この部分が実行されることになる。deviseのコントローラーから呼び出された場合は、「configure_permitted_parameters」メソッドが呼ばれる。

 8
 9
10
def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
end

ここでconfigure_permitted_parametersの定義を行なっている。
deviseをインストールすることでdevise_parameter_sanitizerのpermitメソッドが使えるようになるが、これがストロングパラメータに該当する機能。サインアップ時に入力された「name」キーの内容の保存を許可している。

設定が終わったら、以下のURLにアクセスして正常にビューが表示されることを確認。

http://localhost:3000/users/sign_up

ビューが確認できたら、そのままアカウントを作成してログイン状態にしておく。

https://tech-master.s3.amazonaws.com/uploads/curriculums//e649933b18f327811ba5971c9e1d748b.png

5. ユーザー情報編集機能の追加

登録済みのユーザー情報を編集できるよう機能を追加。
ユーザーの名前とメールアドレスを変更できるようにする。

 コントローラーを作成

まず編集機能の実装に必要なUsersコントローラーを作成。

ターミナル
1
$ rails g controller users

 編集画面のビューを作成

ユーザー情報の編集用のビューを作成。
サインアップ時の画面と似たデザインで実装する。

①app/views/usersフォルダにファイルを新規作成し、「edit.html.haml」と名前をつける
②①のファイルを以下の内容に編集。

app/views/users/edit.html.haml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#account-page.account-page
  .account-page__inner.clearfix
    .account-page__inner--left.account-page__header
      %h2 Edit Account
      %h5 アカウントの編集
      %i.btn ログアウト
      = link_to "トップページに戻る", :back, class: 'btn'
    .account-page__inner--right.user-form
      = form_for(current_user) do |f|
        .field
          .field-label
            = f.label :name
          .field-input
            = f.text_field :name, autofocus: true
        .field
          .field-label
            = f.label :email
          .field-input
            = f.email_field :email
        .actions
          = f.submit "Update", class: 'btn'

ここまでで、コントローラーとビューを作成したが、編集機能の実装には他にも必要な手順がある。

 問題3:ユーザー情報編集機能を実装する

・ユーザー情報の更新が正常にできるようにする
・画面左上に、ログイン中のユーザー名が表示される
・歯車のアイコンをクリックすると、作成した編集ページに遷移する
routes.rb
1
2
3
4
5
6
7
8
9
# ルーティングを追加
Rails.application.routes.draw do
  devise_for :users
  # 下の行は削除する
  # get 'messages/index

  root "messages#index"
  resources :users, only: [:edit, :update]
end
users_controller.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class UsersController < ApplicationController

  def edit
  end

  def update
    if current_user.update(user_params)
      redirect_to root_path
    else
      render :edit
    end
  end

  private

  def user_params
    params.require(:user).permit(:name, :email)
  end
end

 下記の_side_bar.html.hamlのコードは一例。

自身のコードと読み替えて、必要な追記を行う。

shared/_side_bar.html.haml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/ ユーザー編集ページに遷移するためのパスを追加
.side-bar
  .header
    %h3.header__name
      = current_user.name
    %ul.header__lists
      %li.list
        = link_to do
          = icon('fas', 'pen-square', class: 'icon')
      %li.list
        = link_to edit_user_path(current_user) do
          = icon('fas', 'cog', class: 'icon')
  .groups
    .group
      .group__name
        グループ名
      .group__message
        新着メッセージ
    .group
      .group__name
        グループ名
      .group__message
        新着メッセージ
    .group
      .group__name
        グループ名
      .group__message
        新着メッセージ

解説

ユーザー編集機能を実装するため、まずはルーティングを定義。

ユーザーの編集に必要なルーティングは:edit:updateなので、routes.rbに追記。

次に、ルーティングに対応するコントローラのアクションを定義。

users_controller.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class UsersController < ApplicationController

  def edit
  end

  def update
    if current_user.update(user_params)
      redirect_to root_path
    else
      render :edit
    end
  end

  private

  def user_params
    params.require(:user).permit(:name, :email)
  end
end

editアクションでは必要になるインスタンス変数はないので、アクションを定義するだけで大丈夫。

Userモデルの更新を行うupdateアクションは、保存できた場合できなかった場合で処理を分岐。

updateできた場合は「true」が、できなかった場合は「false」が返り値として戻ってくる。それを利用して、if文での分岐ができる。

今回の場合は、current_user.updateに成功した場合、rootにリダイレクトし、失敗した場合、editのビューを再度描画する、という記述になっている。

6. ログアウト機能の追加

現在は、ユーザーの編集画面に「ログアウト」という文字だけが表示されている。

ログアウトをクリックしたら、実際にログアウトされるよう実装する。

 問題4:ログアウト機能を実装する

users/edit.html.haml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#account-page.account-page
  .account-page__inner.clearfix
    .account-page__inner--left.account-page__header
      %h2 Edit Account
      %h5 アカウントの編集
      = link_to "ログアウト", destroy_user_session_path, method: :delete, class: 'btn'
      = link_to "トップページに戻る", :back, class: 'btn'
    .account-page__inner--right.user-form
      = form_for(current_user) do |f|
        .field
          .field-label
            = f.label :name
          .field-input
            = f.text_field :name, autofocus: true
        .field
          .field-label
            = f.label :email
          .field-input
            = f.email_field :email
        .actions
          = f.submit "Update", class: 'btn'

解説

「rake routes」コマンドを実行すると、どのようなリンク先を指定すれば、該当のアクションが動くのか確認できる。

1
destroy_user_session  DELETE  /users/sign_out(.:format) devise/sessions#destroy

該当部分はこのような結果になる。
prefix: 「destroy_user_session_path」
HTTPメソッド: 「DELETE」
を指定すると、sessionsコントローラーのdestroyアクションが実行されることがわかる。

これを、link_toの引数として使用する。

なお、「btn」というクラスはCSSを適用させるためのもの。

 

7. フラッシュメッセージの表示機能の実装

ChatSpaceにメッセージ表示機能を追加する。

ユーザーが、「サインアップ」「ログイン」「ログアウト」を行った直後にメッセージが出るようにする。

 フラッシュメッセージとは

アクションの実行後に簡単なメッセージを表示するRailsの機能。
今回はdeviseの認証関係のメッセージとして使用しますが、その他任意のテキストを表示するためにも使える。

フラッシュメッセージ実装の手順

フラッシュメッセージは、デフォルトでは英語で表示される。以下のステップで実装していく中で、メッセージの日本語化も行う。

①フラッシュメッセージが表示されるようにする
②フラッシュメッセージのスタイリングを行う
③フラッシュメッセージを日本語化する

サインアップ時のフラッシュメッセージ
https://tech-master.s3.amazonaws.com/uploads/curriculums//d1c76d7ee78958731ead8fa66bc152e9.png

サインイン時のフラッシュメッセージ
https://tech-master.s3.amazonaws.com/uploads/curriculums//d505f5d672019080c407ea4a55e2596f.png

ログアウト時のフラッシュメッセージ
https://tech-master.s3.amazonaws.com/uploads/curriculums//2f86710f28e604df5a203e2a7e1a79d8.png

7-1 フラッシュメッセージが表示されるようにする

まずは、メッセージが表示されるまでの実装を行う。

 メッセージ用のビューを追加

まず、フラッシュメッセージを表示するためのビューを作成。

「views/layouts」フォルダの中に、「_notifications.html.hamlと名称で新規作成する。そのファイルに、以下の記述を行う。

app/views/layouts/_notifications.html.haml
1
2
3
.notification
  - flash.each do |key, value|
    = content_tag :div, value, class: key

 flashオブジェクトの使い方

deviseを使用すると、ログイン時などに表示させるメッセージがflashオブジェクト」に自動で格納される。

flashオブジェクト内には、複数のメッセージがハッシュのように「キー」「バリュー」形式で保存されている。

https://tech-master.s3.amazonaws.com/uploads/curriculums//5eb80103008f5163eb28fc0d199198fa.png

each文を使うと、これらを1つずつ取り出すことができ、ChatSpaceでは「キー」を「CSS用のクラス名」に、「バリュー」を「表示するメッセージ本文」として使っている。

 フラッシュメッセージが表示されるようにする

続いて、上記のビューが表示されるよう設定。
application.html.hamlに記述を追加する。

app/views/layouts/application.html.haml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
!!!
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title ChatSpace
    = csrf_meta_tags
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
  %body
    = render 'layouts/notifications'
    = yield

この記述によって、フラッシュメッセージが表示されるようになるが、どのような仕組みで表示がされるのか確認する。

今追記を行なった「application.html.haml」は、どのビューを表示するときも必ず表示されるようデフォルトで設定されているファイル。

このファイルの11行目に「yield」と記述があることに注目。

https://tech-master.s3.amazonaws.com/uploads/curriculums//0ce202f2d86249926904e44b39cd0f53.png

このyieldは、ビューファイルの内容をここに埋め込むために使われている。

例えば、コントローラーのindexアクションが実行され、「index.html.haml」が表示される場面を考える。

まず、「application.html」に書かれた内容は全て表示される。その上で、yieldの部分に「index.html」の内容が埋め込まれ表示される。

この動作によって、indexのビューの上部にフラッシュメッセージが表示されることになる。
実際にログアウトなどを実行し、正しく表示されることを確認する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//d98f23958ab8ec654b0ceb51f0c95b10.png

続いて、このメッセージのデザインを整えていく。

7-2 フラッシュメッセージのスタイリングを行う

フラッシュメッセージのデザインを行うため、scssファイルを追加。

 flash.scssを作成

「stylesheets/config」フォルダに、「colors.scss」という名称でファイルを作り、作成したら、以下のコードを記述。

stylesheets/config/colors.scss
1
2
3
4
5
6
7
$white: #fff;
$side_blue_dark: #253141;
$side_blue_light: #2f3e51;
$light_blue: #38AEF0;
$light_gray: #999;
$black: #434a54;
$alert_orange: #F35500;

続いて、「stylesheets/modules」フォルダに「flash.scss」を作成し設定を行う。「通知用」のメッセージと「アラート用」メッセージでスタイルを分けている。

stylesheets/modules/flash.scss
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.notification {
  .notice {
    background-color: $light_blue;
    color: $white;
    text-align: center;
  }

  .alert {
    background-color: $alert_orange;
    color: $white;
    text-align: center;
  }
}

最後にapplication.scssを編集して、作成した設定ファイルが読み込まれるようにする。

app/assets/stylesheets/application.scss
1
2
3
4
5
6
7
@import "reset";
@import "config/colors";
@import "modules/messages";
@import "font-awesome-sprockets";
@import "font-awesome";
@import "modules/user";
@import "modules/flash";

 colors.scssの読み込みの順番について

colors.scssは、reset.scssの直後で読み込むようにする。

colors.scssには、他のscssで利用している色についての変数が定義されている。
そのため、色についての変数を利用するCSSの前に先に読み込めていないと、エラーになってしまう。

7-3 フラッシュメッセージを日本語化する

 日本語化用のファイルを作成する

「config/locales」フォルダに、「devise.ja.yml」および「ja.yml」という名前のファイルを新規作成。

下記のサイトに記述内容が掲載されているので、それぞれ中身を丸ごとコピーして貼り付け、保存。

https://tech-master.s3.amazonaws.com/uploads/curriculums//e370ffb99a5426e8acd464c739780422.gif

 日本語化のための設定を行う

application.rbを編集して、言語設定を変更する。

config/application.rb
1
2
3
4
5
6
module ChatSpace
  class Application < Rails::Application
    #〜省略〜
    config.i18n.default_locale = :ja
  end
end

 表示を確認する

ここまでの設定が終わったら、仮想サーバーを再起動して正しく日本語でフラッシュメッセージの表示がされることを確認。