FreeCamp      

【Rails】Gem deviseで管理者とユーザーの作成①

Railsでアプリケーションを作成するときに管理者とユーザーを分けたい時があると思います。
今回はGem deviseを用いて管理者とユーザーの2通りを作成します。
また、管理者とユーザーの機能は以下とします。

機能一覧

管理者ログイン(name, password)・ログアウト
投稿の閲覧・編集・削除
ユーザーの閲覧・編集
ユーザー新規登録(name, email, password)・
ログイン(name, password・ログアウト
投稿の閲覧・投稿・編集・削除

目次

  1. ユーザー認証機能・投稿機能
  2. 管理者追加
  3. 管理者とユーザーで画面を分ける
  4. 管理者画面の作成
  5. 権限付与
  6. 完成ソースコード

1. ユーザー認証機能・投稿機能

ユーザー認証機能・投稿機能は下記の記事の完成ソースコードを利用します。
git cloneをし、アプリケーションを試してみましょう。

2. 管理者追加

上記アプリケーションに管理者を追加していきます。
管理者は新規登録フォームは作成しない仕様にするため、seedを利用して初期データを格納します。

$ rails g devise Admin name:string
$ rails db:migrate
Admin.create!(
   name: 'testtest',
   email: 'test@test.com
   password: 'testtest',
)
$ rails db:seed

データが格納できたか確認するために、rails consoleで確かめましょう。

$ rails c // rails consoleは省略できる
$ irb(main):001:0> Admin.all
=> #<ActiveRecord::Relation [#<Admin id: 1, email: "test@test.com", name: "testtest", created_at: "2019-10-20 00:00:00", updated_at: "2019-10-20 00:00:00">]>

作成されているのを確認できましたね。
それでは管理者のviewとコントローラも作成していきます。

$ rails g devise:views admins
$ rails g devise:controllers admins

そして、ルーティングも編集します。

...編集
devise_for :admins
↓
devise_for :admins, controllers: {
  sessions: 'admins/sessions'
}

管理者も名前とパスワードでログインできるようにしましょう。

...編集
<div class="field">
  <%= f.label :email %><br />
  <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
↓
<div class="field">
  <%= f.label :name %><br />
  <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
</div>

ヘッダーのリンクの権限も変えておきます。
現段階だと、管理者でログインした後にユーザーの新規登録・ログインリンクが表示されています。
管理者・ユーザー・それ以外の3つで分けていきます。
そしてヘッダーに管理者かユーザーかゲストユーザーかわかるよう、表示します。

<header>
  <nav>
    <ul>
      <% if user_signed_in? %>
        <li>ユーザー</li>
        <li><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></li>
      <% elsif admin_signed_in? %>
        <li>管理者</li>
        <li><%= link_to "ログアウト", destroy_admin_session_path, method: :delete %></li>
      <% else %>
        <li>ゲストユーザー</li>
        <li><%= link_to "新規登録", new_user_registration_path %></li>
        <li><%= link_to "ログイン", new_user_session_path %></li>
      <% end %>
    </ul>
  </nav>
</header>

管理者はのログインはhttp://localhost:3000/admins/sign_inからアクセスしましょう。

3. 管理者とユーザーで画面を分ける

基本的には管理者とユーザーの見る画面は分けるようにします。
たとえば、投稿一覧を見るにしても管理者はデザイン重視というよりも機能重視にしたり、統計をとったりします。
また、ユーザーはデザインや使いやすさを重視した画面にしたりします。
そして何よりリファクタリングの観点より、管理者とユーザーで画面を分けます。

まずはディレクトリ構造からです。
コントローラもビューもそれぞれadmins, usersディレクトリが存在するので、既存のposts_controller.rbやpostsディレクトリはusersの中に格納しましょう。
格納後、posts_controller.rb・ルーティングを編集します。

...編集
class PostsController < ApplicationController
↓
class Users::PostsController < ApplicationController
...編集
Rails.application.routes.draw do
  devise_for :admins, skip: :all
  devise_scope :admin do
    get 'admins/sign_in' => 'admins/sessions#new', as: 'new_admin_session'
    post 'admins/sign_in' => 'admins/sessions#create', as: 'admin_session'
    delete 'admins/sign_out' => 'admins/sessions#destroy', as: 'destroy_admin_session'    
  end

  devise_for :users, skip: :all
  devise_scope :user do
    get 'users/sign_in' => 'users/sessions#new', as: 'new_user_session'
    post 'users/sign_in' => 'users/sessions#create', as: 'user_session'
    delete 'users/sign_out' => 'users/sessions#destroy', as: 'destroy_user_session'
    get 'users/sign_up' => 'users/registrations#new', as: 'new_user_registration'
    post 'users' => 'users/registrations#create', as: 'user_registration'
    get 'users/password/new' => 'users/passwords#new', as: 'new_user_password'
  end

  namespace :users do
    resources :posts
  end
  root 'users/posts#index'
end

また、namespaceを使用したことにより、名前付きパスのNameErrorが発生します。
エラーが出た場合は「rails routes」を実行して該当ルーティングに編集しましょう。

...編集
<td><%= link_to 'Show', post %></td>
↓
<td><%= link_to 'Show', users_post_path(post) %></td>

<td><%= link_to 'Edit', edit_post_path(post) %></td>
↓
<td><%= link_to 'Edit', edit_users_post_path(post) %></td>

<td><%= link_to 'Destroy', users_post_path(post), method: :delete, data: { confirm: 'Are you sure?' } %></td>
↓
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>

<%= link_to 'New Post', new_post_path %>
↓
<%= link_to 'New Post', new_users_post_path %>
...編集
<%= render 'form', post: @post %>
↓
<%= render 'form', post: @post, url: users_posts_path %>

<%= link_to 'Back', posts_path %>
↓
<%= link_to 'Back', users_posts_path %>
...編集(create, updateアクション両方)
format.html { redirect_to @post, notice: 'Post was successfully created.' }
↓
format.html { redirect_to users_post_path(@post), notice: 'Post was successfully created.' }
...編集
<%= link_to 'Edit', edit_post_path(@post) %>
↓
<%= link_to 'Edit', edit_users_post_path(@post) %>

<%= link_to 'Back', posts_path %>
↓
<%= link_to 'Back', users_posts_path %>
...編集
<%= render 'form', post: @post %>
↓
<%= render 'form', post: @post, url: users_post_path(@post) %>

<%= link_to 'Show', @post %>
↓
<%= link_to 'Show', users_post_path(@post) %>

<%= link_to 'Back', posts_path %>
↓
<%= link_to 'Back', users_posts_path %>
...編集
<%= form_with(model: post, local: true) do |form| %>
↓
<%= form_with(model: post, local: true, url: url) do |form| %>
...編集(destroyアクション)
format.html { redirect_to users_posts_path, notice: 'Post was successfully destroyed.' }
↓
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
...編集
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
↓
<%= link_to "Forgot your password?", new_user_password_path(resource_name) %><br />
...削除
<%= render "admins/shared/links" %>

長かったですね。
これで管理者とユーザーのディレクトリを分けたことによるパスの設定は終わりです。
ここからは管理者の画面を作成していきます。
作成する画面は以下のようになっています。

  • ユーザーの一覧画面
  • ユーザーの詳細画面
  • ユーザーの編集画面
  • 投稿一覧画面
  • 投稿編集画面
  • 投稿詳細画面

まずはじめにadminsディレクトリの中にposts_controller.rbとusers_controller.rbを作成しましょう。

$ rails g controller users index show edit
$ rails g controller posts index show edit

数個のディレクトリやファイルが他のディレクトリ名などと衝突してしまい、
作成できないものもありました。
実装しながら補っていきましょう。
それではcontrollers/adminsディレクトリに先ほど作成したusers_controller.rbとposts_controller.rbを格納しましょう。
そして、views/postsディレクトリをviews/adminsに格納、views/adminsにusersディレクトリを作成し、
views/usersディレクトリ内のedit.html.erbとindex.html.erb, show.html.erbを作成したusersディレクトリに格納しましょう。

以下のようなディレクトリ構成(割愛しているものもあります)になっていれば大丈夫です。

controllers/
   ├ admins
   ├ concerns
   ├ users
   ├ application_controller.rb
   ├ posts_controller.rb
   └ users_controller.rb

views/
   ├ admins/
      ├ posts/
         ├ edit.html.erb
         ├ index.html.erb
         └ show.html.erb
      └ users/
         ├ edit.html.erb
         ├ index.html.erb
         └ show.html.erb
   ├ layouts
   └ users

ルーティングを設定していきます。

...追加
namespace :admins do
  resources :posts
  resources :users
end

posts_controller.rbとusers_controller.rbをadminsディレクトリに格納したので、コントローラも修正します。

...編集
class PostsController < ApplicationController
↓
class Admins::PostsController < ApplicationController
...編集
class UsersController < ApplicationController
↓
class Admins::UsersController < ApplicationController

ここまでで管理者の画面は用意できたので、次の記事では管理者の画面内の整備から始めたいと思います。