学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Rails導入編 | カート機能の実装 | 24 | ログイン

↓↓クリックして頂けると励みになります。




23 | Gメール】 << 【ホーム】 >> 【25 | ユーザー管理





作成したユーザーがログインすることでユーザーの管理機能を使えるように実装します。


まず管理用のユーザ名とパスワードを格納するモデルとデータベーステーブルの作成から始めます。
Digestとは、ハッシュ値を作成するためのモジュールです。
Digestを使えば、ハッシュ値を生成することができます。


ハッシュ値とは、変換して得られるデータです。
データを一方向にしか変換できないのが特徴で、ハッシュ値から元のデータを復元したり、推測したりできないようになっています。
これはパスワードの保存などで用いられます。


ターミナルで以下のコマンドを入力してください。
コマンド
rails generate scaffold User name:string password:digest

~/Desktop/Rails7_1/SampleCart $ rails generate scaffold User name:string password:digest
      invoke  active_record
      create    db/migrate/20240125013726_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      create      app/views/users/_user.html.erb
      invoke    resource_route
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      create      test/system/users_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      create      app/views/users/_user.json.jbuilder



続いてマイグレーションを実行します。
コマンドプロンプトで以下のコマンドを入力してください。
コマンド
rails db:migrate

~/Desktop/Rails7_1/SampleCart $ rails db:migrate

== 20240125013726 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0396s
== 20240125013726 CreateUsers: migrated (0.0398s) =============================



パスワードをハッシュ化させるために「bcrypt」というgemをインストールします。
「Gemfile」に「gem 'bcrypt', '~> 3.1.7'」と記述を追加するか、36行目のコメントアウトを削除します。
今回は36行目のコメントアウトを削除しました。


記述追加 【SampleCart/Gemfile】36行目

source "https://rubygems.org"

ruby "3.1.2"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.1.2"

# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"

# Use postgresql as the database for Active Record
gem "pg", "~> 1.1"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Redis adapter to run Action Cable in production
gem "redis", ">= 4.0.1"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ mswin mswin64 mingw x64_mingw jruby ]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

group :development, :test do
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
  gem "debug", platforms: %i[ mri mswin mswin64 mingw x64_mingw ]
end

group :development do
  # Use console on exceptions pages [https://github.com/rails/web-console]
  gem "web-console"

  # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
  # gem "rack-mini-profiler"

  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
  # gem "spring"

  gem "error_highlight", ">= 0.4.0", platforms: [:ruby]
end

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "selenium-webdriver"
end

gem 'bootstrap', '~> 5.3', '>= 5.3.2'
gem 'sassc-rails', '~> 2.1', '>= 2.1.2'

#日本語化
gem 'rails-i18n', '~> 7.0', '>= 7.0.8'



バンドルインストールを行います。
ターミナルで以下のコマンドを入力してください。
コマンド
bundle install

モデル

作成されたユーザモデルを編集します。
「SampleCart/app/models/user.rb」ファイルを以下のように編集します。
4行目にバリデーションの記述を追加しています。
名前が存在してユニークであること、つまり同じ名前のユーザがデータベースに2人いないかを調べます。
「has_secure_password」はパスワードとその確認フィールドをフォームに表示する機能や指定された名前とパスワードでユーザ認証する機能を実現します。


記述編集 【SampleCart/app/models/user.rb】

class User < ApplicationRecord
  has_secure_password
  
  validates :name, presence: true, uniqueness: true
end


コントローラー

「users_controller.rb」ファイルの編集を行います。
作成(create)の操作を行ったあとにユーザの表示(show)にリダイレクトするのを避けるようにします。
その代わりユーザのindexにリダイレクトしてユーザ名をフラッシュメッセージに追加します。
「create()」「update()」「index()」の3つのメソッドの記述を変更しています。
具体的には6, 28, 41行目の記述を変更しています。


記述編集 【SampleCart/app/controllers/users_controller.rb】

class UsersController < ApplicationController
  before_action :set_user, only: %i[ show edit update destroy ]

  # GET /users or /users.json
  def index
    @users = User.order(:name)
  end

  # GET /users/1 or /users/1.json
  def show
  end

  # GET /users/new
  def new
    @user = User.new
  end

  # GET /users/1/edit
  def edit
  end

  # POST /users or /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to users_url, notice: "ユーザ #{@user.name}を作成しました。" }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /users/1 or /users/1.json
  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to users_url, notice: "ユーザ #{@user.name}を更新しました。" }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1 or /users/1.json
  def destroy
    @user.destroy!

    respond_to do |format|
      format.html { redirect_to users_url, notice: "User was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def user_params
      params.require(:user).permit(:name, :password, :password_confirmation)
    end
end



ユーザーの認証できるようにコントローラーを作成します。
作成するのはログインとログアウトのためのセッションコントローラと管理者を設定するためのコントローラです。


まずはセッションコントローラーを作成します。
ターミナルで以下のコマンドを入力して下さい。
コマンド
rails generate controller Sessions new create destroy

~/Desktop/Rails7_1/SampleCart $ rails generate controller Sessions new create destroy

      create  app/controllers/sessions_controller.rb
       route  get 'sessions/new'
              get 'sessions/create'
              get 'sessions/destroy'
      invoke  erb
      create    app/views/sessions
      create    app/views/sessions/new.html.erb
      create    app/views/sessions/create.html.erb
      create    app/views/sessions/destroy.html.erb
      invoke  test_unit
      create    test/controllers/sessions_controller_test.rb
      invoke  helper
      create    app/helpers/sessions_helper.rb
      invoke    test_unit



Sessionsコントローラのcreateアクションは管理者がログイン済みであることを示す情報をsessionに記録します。
「:user_id」をキーとしてUserオブジェクトのidを格納します。
またログアウトできる様、21行目に「logout()」メソッドを実装します。
このコントローラーはログイン認証を必要としないため3行目に「skip_before_action()」メソッドを追加しています。
「sessions_controller.rb」ファイルを以下のように編集します。


記述編集 【SampleCart/app/controllers/sessions_controller.rb】

class SessionsController < ApplicationController

  skip_before_action :authorize

  def new
  end

  def create
    user = User.find_by(name: params[:name])
    if user.try(:authenticate, params[:password])
      session[:user_id] = user.id
      redirect_to admin_url
    else
      redirect_to login_url, alert: "無効なユーザー/パスワードの組み合わせです。"
    end
  end

  def destroy
  end

  def logout
    reset_session
    @current_user = nil
    redirect_to markets_index_url, notice: "ログアウトしました。"
  end
end



ログイン後のページを表示させるためのAdminコントローラーを作っておきます。
コントローラー編集の必要はありません。
コマンド
rails generate controller Admin index


管理ユーザのみがユーザ管理ページにアクセスできるよう制限をかけます。
これにはRailsのフィルタ機能を使うと簡単に実装できます。
「application_controller.rb」ファイルに記述を追加することで、すべてのコントローラーに適用することができます。


記述変更 【SampleCart/app/controllers/application_controller.rb】

class ApplicationController < ActionController::Base
    
    before_action :authorize

    protected
    def authorize
        unless User.find_by(id: session[:user_id])
            redirect_to login_url, notice: "ログインしてください。"
        end
    end
end



「before_action :authorize」によってこのアプリケーションのすべてのアクションの前に「authorize()」メソッドが呼び出されるようになります。
しかしこれではすべてのアクセスが管理者だけに制限されてしまいます。
認証を必要としないメソッドやコントローラに「skip_before_action()」メソッドの呼び出しを追加します。
「sessions_controller.rb」は先ほど記述してありますので、その他の5つのコントローラーファイル「markets_controller.rb」「carts_controller.rb」「line_items_controller.rb」「orders_controller.rb」「users_controller.rb」に記述を追加します。


記述追加 【SampleCart/app/controllers/markets_controller.rb】3行目

class MarketsController < ApplicationController

  skip_before_action :authorize

  include CurrentCart
  before_action :set_cart

  def index
    @goods = Good.order(:title)
  end
end



記述追加 【SampleCart/app/controllers/carts_controller.rb】3行目

class CartsController < ApplicationController

  skip_before_action :authorize, only: [:create, :update, :destroy]
  
  before_action :set_cart, only: %i[ show edit update destroy ]
  rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart

  # GET /carts or /carts.json
  def index
    @carts = Cart.all
  end

  # GET /carts/1 or /carts/1.json
  def show
  end

  # GET /carts/new
  def new
    @cart = Cart.new
  end

  # GET /carts/1/edit
  def edit
  end

  # POST /carts or /carts.json
  def create
    @cart = Cart.new(cart_params)

    respond_to do |format|
      if @cart.save
        format.html { redirect_to cart_url(@cart), notice: "Cart was successfully created." }
        format.json { render :show, status: :created, location: @cart }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @cart.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /carts/1 or /carts/1.json
  def update
    respond_to do |format|
      if @cart.update(cart_params)
        format.html { redirect_to cart_url(@cart), notice: "Cart was successfully updated." }
        format.json { render :show, status: :ok, location: @cart }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @cart.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /carts/1 or /carts/1.json
  def destroy
    @cart.destroy if @cart.id == session[:cart_id]
    session[:cart_id] = nil

    respond_to do |format|
      format.html { redirect_to markets_index_url, notice: 'カートが空になりました。' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_cart
      @cart = Cart.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def cart_params
      params.fetch(:cart, {})
    end

    def invalid_cart
      logger.error "無効なカート(#{params[:id]})にアクセスしようとしました。"
      redirect_to markets_index_url, notice: '無効なカートです。'
    end
  
end



記述追加 【SampleCart/app/controllers/line_items_controller.rb】3行目

class LineItemsController < ApplicationController

  skip_before_action :authorize, only: :create

  include CurrentCart
	before_action :set_cart, only: [:create]
  before_action :set_line_item, only: %i[ show edit update destroy ]

  # GET /line_items or /line_items.json
  def index
    @line_items = LineItem.all
  end

  # GET /line_items/1 or /line_items/1.json
  def show
  end

  # GET /line_items/new
  def new
    @line_item = LineItem.new
  end

  # GET /line_items/1/edit
  def edit
  end

  # POST /line_items or /line_items.json
  def create
    good = Good.find(params[:good_id])
    @line_item = @cart.add_good(good)

    respond_to do |format|
      if @line_item.save
        format.html { redirect_to markets_index_url, notice: "商品をカートに追加しました。" }
        format.js
        format.json { render :show, status: :created, location: @line_item }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /line_items/1 or /line_items/1.json
  def update
    respond_to do |format|
      if @line_item.update(line_item_params)
        format.html { redirect_to line_item_url(@line_item), notice: "Line item was successfully updated." }
        format.json { render :show, status: :ok, location: @line_item }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /line_items/1 or /line_items/1.json
  def destroy
    @line_item.destroy!

    respond_to do |format|
      format.html { redirect_to line_items_url, notice: "Line item was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_line_item
      @line_item = LineItem.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def line_item_params
      params.require(:line_item).permit(:good_id)
    end
end



記述追加 【SampleCart/app/controllers/orders_controller.rb】3行目

class OrdersController < ApplicationController

  skip_before_action :authorize, only: [:new, :create]

  include CurrentCart
  before_action :set_cart, only: [:new, :create]
  before_action :ensure_cart_isnt_empty, only: :new
  before_action :set_order, only: [:show, :edit, :update, :destroy]

  # GET /orders or /orders.json
  def index
    @orders = Order.all
  end

  # GET /orders/1 or /orders/1.json
  def show
  end

  # GET /orders/new
  def new
    @order = Order.new
  end

  # GET /orders/1/edit
  def edit
  end

  # POST /orders or /orders.json
  def create
    @order = Order.new(order_params)
    @order.add_line_items_from_cart(@cart)

    respond_to do |format|
      if @order.save
        Cart.destroy(session[:cart_id])
        session[:cart_id] = nil
        OrderMailer.received(@order).deliver_later
        format.html { redirect_to markets_index_url, notice: '商品が注文されました。' }
        format.json { render :show, status: :created, location: @order }
      else
        format.html { render :new }
        format.json { render json: @order.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /orders/1 or /orders/1.json
  def update
    respond_to do |format|
      if @order.update(order_params)
        format.html { redirect_to order_url(@order), notice: "注文が変更されました。" }
        format.json { render :show, status: :ok, location: @order }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @order.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /orders/1 or /orders/1.json
  def destroy
    @order.destroy!

    respond_to do |format|
      format.html { redirect_to orders_url, notice: "注文を削除しました。" }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_order
      @order = Order.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def order_params
      params.require(:order).permit(:name, :address, :email, :pay_type)
    end

    def ensure_cart_isnt_empty
      if @cart.line_items.empty?
        redirect_to markets_index_url, notice: '商品がカートに入っていません。'
      end
    end    
end



ユーザ登録後にリダイレクトするリンクも合わせて修正しています。
記述編集 【SampleCart/app/controllers/users_controller.rb】3, 31, 44行目

class UsersController < ApplicationController

  skip_before_action :authorize, only: [:new, :create]

  before_action :set_user, only: %i[ show edit update destroy ]

  # GET /users or /users.json
  def index
    @users = User.order(:name)
  end

  # GET /users/1 or /users/1.json
  def show
  end

  # GET /users/new
  def new
    @user = User.new
  end

  # GET /users/1/edit
  def edit
  end

  # POST /users or /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to markets_index_url, notice: "ユーザ #{@user.name}を作成しました。" }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /users/1 or /users/1.json
  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to markets_index_url, notice: "ユーザ #{@user.name}を更新しました。" }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1 or /users/1.json
  def destroy
    @user.destroy!

    respond_to do |format|
      format.html { redirect_to users_url, notice: "User was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def user_params
      params.require(:user).permit(:name, :password, :password_confirmation)
    end
end



これでユーザ管理ページ以外はアクセス制限されないようになりました。

ルート

ルートの設定をします。
「SampleCart/config/routes.rb」ファイルを編集します。
セッションの設定は以下の部分になります。

  get '/login',   to: 'sessions#new'
  get '/logout',  to: 'sessions#logout'

  post   '/login',   to: 'sessions#create'



記述編集 【SampleCart/config/routes.rb】

Rails.application.routes.draw do
  
  #action cable
  mount ActionCable.server => '/cable'

  #root
  root 'markets#index', as: 'markets_index'

  # get
  get 'markets/index'
  get 'says/hello'
  get 'says/goodby'
  get 'admin', to: 'admin#index'
  get '/login',   to: 'sessions#new'
  get '/logout',  to: 'sessions#logout'

  # post
  post   '/login',   to: 'sessions#create'

  #resources
  resources :goods
  resources :orders
  resources :line_items
  resources :carts
  resources :users

  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
  # Can be used by load balancers and uptime monitors to verify that the app is live.
  get "up" => "rails/health#show", as: :rails_health_check

  # Defines the root path route ("/")
  # root "posts#index"
end


ビュー

ユーザ登録用のフォームを作成します。
レンダーファイル「SampleCart/app/views/users/_form.html.erb」を以下のように編集します。


記述編集 【SampleCart/app/views/users/_form.html.erb】

<%= form_with(model: user) do |form| %>
  <% if user.errors.any? %>
    <div style="color: red">
      <h2>エラーが<%= pluralize(user.errors.count, "件") %>あります。下記の項目を修正してください。</h2>

      <ul>
        <% user.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="input-group mb-3 w-75">
    <span class="input-group-text">ユーザ名</span>
    <%= form.text_field :name, class: "form-control" %>
  </div>

  <div class="input-group mb-3 w-75">
    <span class="input-group-text">パスワード</span>
    <%= form.password_field :password, class: "form-control" %>
  </div>

  <div class="input-group mb-3 w-75">
    <span class="input-group-text">パスワード(確認)</span>
    <%= form.password_field :password_confirmation, class: "form-control" %>
  </div>

  <div>
    <%= form.submit "登録", class: "btn btn-primary" %>
  </div>
<% end %>



次にユーザ登録ビューを編集します。
「SampleCart/app/views/users/new.html.erb」ファイルを以下のように編集します。


記述編集 【SampleCart/app/views/users/new.html.erb】

<div class="container mt-4">
  <div class="h4 mt-4 mb-4">ユーザ登録</div>

  <%= render "form", user: @user %>

  <br>

  <div>
    <%= link_to "登録ユーザ一覧", users_path, class: "btn btn-success" %>
  </div>
</div>



ブラウザでユーザー登録フォームを確認します。
ブラウザ確認
http://localhost:3000/users/new

ユーザ登録
ユーザ登録





フォームにユーザ名とパスワードを入力してユーザを登録します。

ユーザー登録完了
ユーザー登録完了



Posticoでユーザーテーブルを確認してみます。
Windowsの場合はHeidiSQLで確認してください。
パスワードがハッシュ化されて保存されているのがわかります。

ユーザーテーブル確認
ユーザーテーブル確認



ログイン用のビューを編集します。
「SampleCart/app/views/sessions/new.html.erb」ファイルを以下のように編集してください。


記述編集 【SampleCart/app/views/sessions/new.html.erb】

<div class="container mt-4">
    <div class="h4 mb-4">
        ログイン
    </div>

    <%= form_tag do %>
        <div class="input-group mb-3 w-75">
            <span class="input-group-text">ユーザ名</span>
            <%= text_field_tag :name, params[:name], class: "form-control" %>
        </div>

        <div class="input-group mb-3 w-75">
            <span class="input-group-text">パスワード</span>
            <%= password_field_tag :password, params[:password], class: "form-control" %>
        </div>

        <div>
            <%= submit_tag "ログイン", class: "btn btn-primary" %>
        </div>
    <% end %>

</div>



ログイン後に表示されるビューを編集します。
「SampleCart/app/views/admin/index.html.erb」ファイルを以下のように編集します。


記述編集 【SampleCart/app/views/admin/index.html.erb】

<div class="container mt-4">
    <div class="h4">
        ログイン中
    </div>
    <p>
        現在時刻は<%= Time.now %>です。<br/>
        現在<%= pluralize(@total_orders, "件") %>の注文があります。
    </p>
</div>



ではログインの動作を確認します。
ログインしていない状態で以下のURLにアクセスします。
ログインしてくださいと表示され、ログインページにリダイレクトされます。
http://localhost:3000/carts/show

ログインページにリダイレクト
ログインページにリダイレクト



ログインすると、ログイン中と表示されます。

ログイン成功
ログイン成功



この状態(ログインしている状態)で先ほどのURLにアクセスすると、「無効なカートです」と表示される様になります。
http://localhost:3000/carts/show

>

無効なカートです
無効なカートです



ログアウトします。
URLに以下のアドレスを入力してください。
ログアウトしましたと表示されます。
http://localhost:3000/logout

ログアウト成功
ログアウト成功



また先ほどのURLにアクセスすると、ログインしてくださいと表示されるはずです。
http://localhost:3000/carts/show


ログインボタンとログアウトボタンを実装します。
「SampleCart/app/views/shared/_navbar.html.erb」ファイルを以下のように編集します。


記述編集 【SampleCart/app/views/shared/_navbar.html.erb】14, 26行目

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="/">Smple Cart</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <!-- もしログインしていなかったら-->
        <li class="nav-item" style="margin-bottom: 0.1rem;">
            <span style="margin-left: 3rem;"><a class="btn btn-danger">新規登録</a></span>
        </li>
        <li class="nav-item">
          <span style="margin-left: 3rem;"><%= link_to  "ログイン", login_path, class: "btn btn-success text-light" %></span>
        </li>
    </ul>
    <ul class="navbar-nav mr-auto w-25">
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            ドロップダウン
          </a>
          <ul class="dropdown-menu">
            <li><a class="dropdown-item" href="#">Action</a></li>
            <li><a class="dropdown-item" href="#">Another action</a></li>
            <li><hr class="dropdown-divider"></li>
            <li><%= link_to  "ログアウト", logout_path, class: "dropdown-item btn btn-light" %></li>
          </ul>
        </li>
      </ul>
    </div>
  </div>
</nav>



これでログインボタンとログアウトボタンが実装されました。

ログインボタンとログアウトボタン
ログインボタンとログアウトボタン



23 | Gメール】 << 【ホーム】 >> 【25 | ユーザー管理




↓↓クリックして頂けると励みになります。