学習の書き留め プログラミング勉強中

プログラミングで学んだことを日記として残して行こうと思います

今日の学習

今日学んだこと 2021/02/04

学習項目

devise応用

学習内容

エンジニアの方から、色々教えていただいたので、学習の書き留めとして残したいと思います。
実装内容
userとadmin(管理者)のdevise管理
個別のルーティング
個別のコントローラ(継承)
個別ページ
になります

devise導入

まずはアプリを作るところから
お好みだと思いますが、とりあえずバージョン6.0.0のmysqlで作ります。

rails _6.0.0_ new test_devise -d mysql

その後に、データベースの文字コードを少し変更
config/database.yml

default: &default
  adapter: mysql2
  # encoding: utf8mb4
  encoding: utf8 #ここをutf8に変える
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

からのデータベース作成

cd test_devise
rails db:create

今回はdeviseのトレーニングですので、deviseをインストールします。
順番としては
1 Gemファイルにdeviseを記述
2 bundle install 3 rails g devise:install

# Gemfile
gem 'devise'

#コンソール
bundele install
rails g devise:install

rails g devise:installをすると

Depending on your application's configuration some manual setup may be required:
......

と言った記述があると思います。
設定方法について説明してくれているのですが、今回は3の

3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

に従います。
これは何なのかと言うと、viewsのアプリケーションファイルにpの記述をすると、ログインした後とかに、
ログイン成功しましたとかを書いてくれます。優秀!!!

と言うわけで、
app/views/layouts/application.html.erb.

<!DOCTYPE html>
<html>
  <head>
    <title>TestDevise2</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>
    <p class="notice"><%= notice %></p> #今回はとりあえず、yieldの上にしました。
    <p class="alert"><%= alert %></p>
    <%= yield %>
  </body>
</html>

これでオッケーです。

deviseを本格的に動かしたいところですが、その前にホームページを簡単に作ります。

#config/routes.rb
Rails.application.routes.draw do
  root to: 'hello#index'
end

#app/controllers/hello_controller.rb
class HelloController < ApplicationController
end

#app/views/hello/index.html.erb
hello world

まあ手書きしましたが、rails g controller hello index
でもどちらでも大丈夫です。

devise操作

ではここから本格的にdeviseを使っていきたいと思います。
まずは、user,adminの両方のmodel, controller, viewを作ります。
その後にマイグレートを行ってください。

#model
rails g devise user
rails g devise admin

#controller
rails g devise:controllers users
rails g devise:controllers admins

#view
rails g devise:views users
rails g devise:views admins

rails db:migrate

これで、あらかたできたのですが、rails routesをみると

                    new_admin_session GET    /admins/sign_in(.:format)                                                                devise/sessions#new
                        admin_session POST   /admins/sign_in(.:format)                                                                devise/sessions#create
                destroy_admin_session DELETE /admins/sign_out(.:format)                                                               devise/sessions#destroy
                   new_admin_password GET    /admins/password/new(.:format)                                                           devise/passwords#new
                  edit_admin_password GET    /admins/password/edit(.:format)                                                          devise/passwords#edit
                       admin_password PATCH  /admins/password(.:format)                                                               devise/passwords#update
                                      PUT    /admins/password(.:format)                                                               devise/passwords#update
                                      POST   /admins/password(.:format)                                                               devise/passwords#create
            cancel_admin_registration GET    /admins/cancel(.:format)                                                                 devise/registrations#cancel
               new_admin_registration GET    /admins/sign_up(.:format)                                                                devise/registrations#new
              edit_admin_registration GET    /admins/edit(.:format)                                                                   devise/registrations#edit
                   admin_registration PATCH  /admins(.:format)                                                                        devise/registrations#update
                                      PUT    /admins(.:format)                                                                        devise/registrations#update
                                      DELETE /admins(.:format)                                                                        devise/registrations#destroy
                                      POST   /admins(.:format)                                                                        devise/registrations#create
                     new_user_session GET    /users/sign_in(.:format)                                                                 devise/sessions#new
                         user_session POST   /users/sign_in(.:format)                                                                 devise/sessions#create
                 destroy_user_session DELETE /users/sign_out(.:format)                                                                devise/sessions#destroy
                    new_user_password GET    /users/password/new(.:format)                                                            devise/passwords#new
                   edit_user_password GET    /users/password/edit(.:format)                                                           devise/passwords#edit
                        user_password PATCH  /users/password(.:format)                                                                devise/passwords#update
                                      PUT    /users/password(.:format)                                                                devise/passwords#update
                                      POST   /users/password(.:format)                                                                devise/passwords#create
             cancel_user_registration GET    /users/cancel(.:format)                                                                  devise/registrations#cancel
                new_user_registration GET    /users/sign_up(.:format)                                                                 devise/registrations#new
               edit_user_registration GET    /users/edit(.:format)                                                                    devise/registrations#edit
                    user_registration PATCH  /users(.:format)                                                                         devise/registrations#update
                                      PUT    /users(.:format)                                                                         devise/registrations#update
                                      DELETE /users(.:format)                                                                         devise/registrations#destroy
                                      POST   /users(.:format)                                                                         devise/registrations#create
                                 root GET    /                                                                                        hello#index

となっています。こうなってしまうとuserもadminも全てdeviseのコントローラを経由してしまい、別々で処理ができません。
ですのでroutesをいじります。

Rails.application.routes.draw do
  devise_for :admins, controllers: {
    sessions:      'admins/sessions',
    passwords:     'admins/passwords',
    registrations: 'admins/registrations'
  }
  devise_for :users, controllers: {
    sessions:      'users/sessions',
    passwords:     'users/passwords',
    registrations: 'users/registrations'
  }
  root to: 'hello#index'
end

ほんとはadminは登録できない方がいいので後で消します。
こうすると、routesは

                    new_admin_session GET    /admins/sign_in(.:format)                                                                admins/sessions#new
                        admin_session POST   /admins/sign_in(.:format)                                                                admins/sessions#create
                destroy_admin_session DELETE /admins/sign_out(.:format)                                                               admins/sessions#destroy
                   new_admin_password GET    /admins/password/new(.:format)                                                           admins/passwords#new
                  edit_admin_password GET    /admins/password/edit(.:format)                                                          admins/passwords#edit
                       admin_password PATCH  /admins/password(.:format)                                                               admins/passwords#update
                                      PUT    /admins/password(.:format)                                                               admins/passwords#update
                                      POST   /admins/password(.:format)                                                               admins/passwords#create
            cancel_admin_registration GET    /admins/cancel(.:format)                                                                 admins/registrations#cancel
               new_admin_registration GET    /admins/sign_up(.:format)                                                                admins/registrations#new
              edit_admin_registration GET    /admins/edit(.:format)                                                                   admins/registrations#edit
                   admin_registration PATCH  /admins(.:format)                                                                        admins/registrations#update
                                      PUT    /admins(.:format)                                                                        admins/registrations#update
                                      DELETE /admins(.:format)                                                                        admins/registrations#destroy
                                      POST   /admins(.:format)                                                                        admins/registrations#create
                     new_user_session GET    /users/sign_in(.:format)                                                                 users/sessions#new
                         user_session POST   /users/sign_in(.:format)                                                                 users/sessions#create
                 destroy_user_session DELETE /users/sign_out(.:format)                                                                users/sessions#destroy
                    new_user_password GET    /users/password/new(.:format)                                                            users/passwords#new
                   edit_user_password GET    /users/password/edit(.:format)                                                           users/passwords#edit
                        user_password PATCH  /users/password(.:format)                                                                users/passwords#update
                                      PUT    /users/password(.:format)                                                                users/passwords#update
                                      POST   /users/password(.:format)                                                                users/passwords#create
             cancel_user_registration GET    /users/cancel(.:format)                                                                  users/registrations#cancel
                new_user_registration GET    /users/sign_up(.:format)                                                                 users/registrations#new
               edit_user_registration GET    /users/edit(.:format)                                                                    users/registrations#edit
                    user_registration PATCH  /users(.:format)                                                                         users/registrations#update
                                      PUT    /users(.:format)                                                                         users/registrations#update
                                      DELETE /users(.:format)                                                                         users/registrations#destroy
                                      POST   /users(.:format)                                                                         users/registrations#create
                                 root GET    /                                                                                        hello#index

となるのでそれぞれに対応した動きをすることができます。

adminの登録を消す

管理者はおいそれと新規登録できない方がいいので消したいと思います。
とりあえず挙動確認は必要なので、/admins/sign_upから1名だけ登録してください。
その後に、#app/models/admin.rbから

class Admin < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable, #←こいつを消す
         :recoverable, :rememberable, :validatable
end

registerableは新規登録に関わるものですので、消すないしはコメントアウトすることで、
以後urlを消すことができます。
そのほか、routesやviewファイルは消してしまって大丈夫です。

これで、例えば、userのログイン後に行き先をroot以外にしたい場合は

#app/controllers/users/sessions_controller.rb

protected #最後に記述する

  def after_sign_in_path_for(resource)
    #ログイン後移動させたい場所のパス
  end

で実装することができます。

ホームページを整える

現在、どっちのログインをしているかがわからないので、まず整えようと思います。

<% if user_signed_in? %>
<p><%= link_to"user:#{current_user.email} ログアウト", destroy_user_session_path, method: :delete %></p>
<% elsif admin_signed_in? %>
<p><%= link_to"admin:#{current_admin.email} ログアウト", destroy_admin_session_path, method: :delete %></p>
<% else %>
<p>not_login</p>
<% end %>

<p><%= link_to 'adminログイン', new_admin_session_path %></p>
<p><%= link_to 'userログイン', new_user_session_path %></p>
<p><%= link_to 'user登録', new_user_registration_path %></p>

これで、ログインないし、新規登録もでき、現在のログイン者もわかるようになったと思います。

個別のルーティング

個別のルーティングですが、各々のサービスで、ユーザーはユーザーのページ、管理者は管理者のページがあると管理しやすいと思いますので、
それを作っていきます。 それぞれ、ダッシュボードに行くことを目標とします。

まず、routesを

Rails.application.routes.draw do
  devise_for :admins, controllers: {
    sessions:      'admins/sessions',
    passwords:     'admins/passwords'
  }
  devise_for :users, controllers: {
    sessions:      'users/sessions',
    passwords:     'users/passwords',
    registrations: 'users/registrations'
  }
  root to: 'hello#index'

  namespace :users do
    resource :dashboards, only: [:show]
  end
  
  namespace :admins do
    resource :dashboards, only: [:show]
  end
end

と編集し、namespaceごとに分けてあげます。
そうすると、

users_dashboards_path  GET    /users/dashboards(.:format)   users/dashboards#show
admins_dashboards_path  GET    /admins/dashboards(.:format)  admins/dashboards#show

この二つのroutesが追加されたはずです。
これに合わせてcontrollerを作っていきます。 今回はuserに合わせて作っていきます ファイルの作り方は、

app/controllers/users/dashboards_controller.rb

と、userにdashboards_controller.rb記述します。 また、今回それぞれの動きに合わせて、共通処理も書いていきたいので、一緒に

rails g controller users

でuserコントローラーも作っておきます。
ここから、dashboards_controller.rbの書き方ですが、
userを通ること示すために、

module Users

end

とまず書きます。
または

class Users::

を頭につけます。

その後に、userコントローラを継承するので、最終的に、

module Users
  class DashboardsController < UsersController
    def show
    end
  end
end

#または

  class Users::DashboardsController < UsersController
    def show
    end
  end

と言う書き方になります。ちなみにmoduleの方が一般的らしいです。 showページはapp/views/users/dashboards/show.html.erb
とdashboardsフォルダを作って、そこにshowファイルを作ります。

共通の処理を記述する

今回、ログインしていた場合、showファイルを見れるようにするとした場合、
showファイルに書くのもいいですが、今後実装するものが増えた時に新しいcontrollerに毎回書かないといけなくなります。 Userコントローラを作って継承したので、そこに書いて、一回で済むようにしましょう。

class UsersController < ApplicationController
  before_action :login_check

    private

    def login_check
      unless user_signed_in?
        flash[:alert] = "ログインしてください"
        redirect_to new_user_session_path
      end
    end
end

これで、controllerが今後増えても、継承していけば、実装しなくてすみます。 共通の処理でいうと、サービスクラスがありますが、
サービスクラスは一連の動作をまとめたものですので、継承との処理をまとめるのは毛色が違います。

個別ページ

最後にユーザーのダッシュボードに飛んだ場合、レイアウトを変えたかったとします。
その場合は、app/views/layouts/application.html.erbをコピーして、 app/views/layouts/users.html.erbにします。
例えばファイルの中身を

<!DOCTYPE html>
<html>
  <head>
    <title>TestDevise2</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>
    <p>ここだよここuserの時は追加されるよ!</p>
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
    <%= yield %>
  </body>
</html>

とすると、userコントローラを通るもののビューページは全てこれが適用されます。
また、意図的に変えたいレイアウトがある場合、controllerで

layout "変えたいレイアウト名"

にすると、変更ができます。

まとめ

実際に応用をするとすごく難しいけど、楽しい!!
これを引き出しにできるようにする。