今日の学習
今日学んだこと 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 "変えたいレイアウト名"
にすると、変更ができます。
まとめ
実際に応用をするとすごく難しいけど、楽しい!!
これを引き出しにできるようにする。