PROGRAMMING

Rails ECサイトでAdminアカウントを追加する方法

RailsでECサイトのAdmimアカウントを追加し、商品を登録出来る方法を紹介していきたいと思います。

adminアカウントとは、管理者用のアカウントですね!

誰でもECサイトの商品を追加できないように、管理者用のアカウントを作り、UserアカウントとAdminアカウントを分ける必要があります。

作業内容
・Adminアカウントでログインを可能にする
・Admin がログインしたら /admins という Admin がログインしないと見れないページ(ダッシュボード)にリダイレクトする
・AdminアカウントはRails consoleからしか作成できないようにする(勝手に利用者が登録できないようにする)
・Admin画面で商品を登録できるようにする

以上が今回やっていく作業内容です。

作業手順

devise:Adminの追加

まずはAdminアカウントを追加するためにdeviseでAdminアカウントを追加していきます。

下記のコードをコンソールに入力します。

$rails g devise Admin
$rails db:migrate

下記のようにroute.rbdevise_for :adminsが自動的に追加されましたね。

Rails.application.routes.draw do
devise_for :admins
devise_for :users

その次にModelを見てみましょう。Adminモデルにもこんな感じで追加されてました。今回はconsoleからしか登録できないようにしたいので、:registerableは消しちゃいます。誰でも登録できないようにするためですね。

class Admin < ApplicationRecord
  devise :database_authenticatable, 
         :recoverable, :rememberable, :validatable
end

それではAdminのアカウントを作成してみましょう。db/seeds.rbファイルに記入して、コンソールで$ rails db:seedを追加すればすぐにアカウントを作成することができます。

Admin.create!(
    email: 'test@test.com',
    password: '******',
)
$ rails db:seed

コンソールの方で実際にアカウントが作られているのかどうかをみてみます。確認方法はAdmin.allでもAdmin.lastでもどちらでも大丈夫です。

$ rails c
2.5.3 :001 > Admin.all
 => #<ActiveRecord::Relation [#<Admin id: 1, email: "test@test.com", created_at: "2020-10-08 14:32:06", updated_at: "2020-10-08 14:32:06">]> 

無事に作られていますね。

Adminトップページの作成

それではルーティングを作っていきましょう!

私の作業の進め方はモデル→マイグレーション→ルーティング→コントローラー→ビューの順番で進めていきますので、今回もこの順番で進めていきます。

Adminアカウントでログインした後のAdmin専用のトップページを作成したいので、下記のようにルーティングします。

  namespace :admins do
    root "toppages#index"
  end

URLはこれで/adminsになります。

$rails routesを入力して、きちんとルーティングできているかどうかを見てみましょう。

admin_root GET  /admins(.:format) admins/toppages#index

上記のようになっていれば大丈夫です。

これで/adminsのというURLが完成しました。次に、controllerviewsを設定していこうと思います。

コントローラーとビューの作成

adminsの元にtoppagesを作りたいので、以下のようにコンソールに追加します。

$rails g controller admins/toppages index

次に、新しくadmins/application_controller.rbというファイルを作成します。ディレクトリがadminsのため、上記のようにAdmins::と名前空間を追加します。

class Admins::ApplicationController < ApplicationController
end

そしたらtoppages_controller.rbにもAdmin::を追加します。

class Admins::ToppagesController < Admin::ApplicationController
  def index
  end
end

controllerとviewsにコードを追加していきたいのですが、その前にまずはログインして/adminsに入れるか見てみましょう。

画像に alt 属性が指定されていません。ファイル名: b045d2db6e23e543be4202e156abf4e1.png

上の画像ではナビゲーションバーがログイン前とログイン後で変化していないので、変更できるようにしましょう。

<header class="mb-4">
  <nav class="navbar navbar-expand-sm navbar-light p-4"style="background-color: #e3f2fd">
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse justify-content-end" id="navbarSupportedContent">
      <ul class="navbar-nav">
        <% if user_signed_in? %>
              <li class="nav-item dropdown">
                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown"></a>
                <ul class="dropdown-menu dropdown-menu-right">
                  <li class="dropdown-divider"></li>
                  <li class="dropdown-item"><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></li>
                </ul>
              </li>
        <% elsif admin_signed_in? %>
              <li class="nav-item dropdown">
                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown"></a>
                <ul class="dropdown-menu dropdown-menu-right">
                  <li class="dropdown-divider"></li>
                  <li class="dropdown-item"><%= link_to "ログアウト", destroy_admin_session_path, method: :delete %></li>
                </ul>
              </li>
        <% else %>
          <li class="nav-item"><%= link_to 'Signup', new_user_registration_path, class: 'nav-link' %></li>
          <li class="nav-item"><%= link_to 'Login', new_user_session_path, class: 'nav-link' %></li>
        <% end %>
      </ul>
    </div>
  </nav>
</header>

<% elsif admin_signed_in? %>を追加することでAdminアカウントのログアウト機能をナビゲーションバーに追加することできました。

それではcontrollerとviewsにコードを追加していきます。

Adminに商品登録機能をつける

admin/products/newという感じにしたいため、productadminreferencesをつけます。しかし、productsのマイグレーションファイルをadminより先に作ってしまっているため、ファイルの順番を入れ替える必要があります。そのため、下記のように日付を変えてあげると、順番を変更できます

<before>
20200913131359_create_products.rb
20201009140157_devise_create_admins.rb
⬇️
<after>
20200909140157_devise_create_admins.rb
20200913131359_create_products.rb

productsのマイグレーションにadminreferencesがを追加します。

class CreateProducts < ActiveRecord::Migration[5.2]
  def change
    create_table :products do |t|
      t.references :admin, foreign_key: true
      t.references :user, foreign_key: true
      t.string :name, :null => false
      t.text :description, :null => false
      t.integer :price, :null => false

      t.timestamps
    end
  end
end

このままだとマイグレーションができないので、一旦データベースをリセットしていきます。

$ rails db:migrate:reset

無事マイグレーションができましたら、また再度アカウントを作ります。

$ rails db:seed

アカウントが無事作られたら、モデルの関連性を追加します。

class Admin < ApplicationRecord
  has_many :products, dependent: :destroy
end

class Product < ApplicationRecord
  belongs_to :admin
end

モデルに関連性ができたらコントローラーを作成していきます。

そのまえにルーティングの設定をします。

ルーティングの設定

adminsの元にproductsを追加していきます。下記のようにルーティングにproductsを追加します。

Rails.application.routes.draw do
devise_for :admins
devise_for :users
  root to: "products#index"
  
  resources :products, only: [:show] do
    scope module: :products do
      resources :add_to_carts, only: [:create]
      resources :delete_in_carts, only: [:create]
    end
  end
      
  resource :cart, only: [:show] 
  
  resource :charge, only: [:create]

   namespace :admins do
      root to: "toppages#index"
      resources :products, only: [:new, :create]
   end
end

下記のようになればOKです。

adminsの配下にproductsを置くことができました。それでは、app/admins/products_controller.rbをを作成していきます。

コントローラーの作成

productsのコントローラーを追加していきます。

class Admins::ProductsController < Admins::ApplicationController
end

既にadmins/applicationControllerは作成しているので、class Admins::ProductsController < ApplicationControllerではなく、class Admins::ProductsController < Admins::ApplicationControllerとなります。

それではこのcontrollerで商品登録をし、元々あるproductscontrollerからnewcreateを移します。

class ProductsController < ApplicationController
  
  def index
    @products = Product.order(id: :desc).page(params[:page]).per(10)
  end

  def show
    @product = Product.find(params[:id])
  end
end
class Admins::ProductsController < Admins::ApplicationController
  def new
    @product = current_admin.products.build
  end
  
  def create
    @product = current_admin.products.build(product_params)
      if @product.save
          flash[:success] = "Productが正常に作成されました"
          redirect_to root_path
      else
          flash.now[:danger] = "Productが正常に再生されませんでした"
          render :new
      end
  end
  
  private
  
  def product_params
      params.require(:product).permit(:name, :description, :price, :image)
  end
end

current_userの部分を全てcurrent_adminに変更しただけですね。

ビューの作成

こちらもUserアカウント用からAdminアカウント用の商品追加機能に変更します。

<h1>新規商品の追加</h1>

<%= simple_form_for [:admins,@product] do |f| %>
    <div class="form-group">
      <%= f.label :name, '*Name' %>
      <%= f.text_field :name ,class: 'form-control' %>
    </div>
    <div class="form-group">
      <%= f.label :description, '*Description' %>
      <%= f.text_field :description ,class: 'form-control' %>
    </div>
    <div class="form-group">
      <%= f.label :price, '*Price' %>
      <%= f.text_field :price ,class: 'form-control' %>
    </div>
    <div class="form-group">
      <%= f.label :image, 'image' %>
      <%= f.file_field :image %>
    </div>
  <%= f.button :submit, "CREATE PRODUCT", :class => 'btn' %>
<% end %>

<%= simple_form_for @product do |f| %>が元々のコードですが、これだとproducts_pathにリクエストを送ることになってしまします。namespaceの場合は、<%= simple_form_for [:admins,@product] do |f| %>このようにするとadmins_products_pathにリクエストを送れます。

"CREATE PRODUCT"ボタンを押すと、無事商品が登録されました。

Adminアカウントがログインしないと使えないようにする

ログインしないと商品を登録できないようにするために、下記のようにします。

class Admins::ApplicationController < ApplicationController
    before_action :authenticate_admin!
end

before_action :authenticate_user!と同じですね。これのadminバージョンです。

ログイン直後とログアウト直後のページを指定する

現状、ログイン直後は全てproducts#indexになってしまっているので、下記のようにApplicationControllerを変更します。

class ApplicationController < ActionController::Base
 def after_sign_in_path_for(resource)
    if resource.is_a?(Admin)
      admins_root_path
    else
      root_path
    end
end

def after_sign_out_path_for(resource)
    if resource == :admin
      new_admin_session_path
    else
      new_user_session_path
    end
  end
end

resource.is_a?(Admin)というのはresourceAdmin のインスタンスであれば true を返すという処理です。要するに、 resourceDevise に定義されているアカウントのクラスのインスタンスを意味します。

Adminでログインすると/adminsに無事リダイレクトされました!

まとめ

以上がECサイトのAdminアカウントの追加方法です!

今回の記事ではnamespaceを使っているので、namespaceのいい勉強になると思います。

僕も最初はnamespaceについての理解が難しかったのですが、調べて自分でアウトプットしていくと理解が深くなりました。

ECサイトはいろんな機能があるので、ものすごく勉強になります。

プログラミングの勉強の際に、この記事を参考にして頂けると幸いです。

最後まで読んで頂きありがとうございました。

-PROGRAMMING

Copyright © Iseblog ,@2020 All Rights Reserved.