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

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

Rails7.1 | 動画学習アプリ作成 | 34 | raty-js

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




33 | クレジットカード決済の実装】 << 【ホーム】 >> 【35 | ホームページ




raty-jsは、スター評価を作成するためのJavaScriptプラグインです。
Rails7.1でraty-jsを利用するには、以下のステップに従って設定を行う必要があります。


「star-on.png」「star-off.png」「star-half.png」の3ファイルを「app/assets/images」フォルダにコピーしておいてください。


画像は下記のリンクにあります。
github.com


「raty-js」をインストールします。

Rails6.1ではyarnを利用していましたが、Rails7.1ではimportmapを利用しまし。
しかしながら、使用するJQueryがimportmapでうまく動作しないため、raty-jsも「app/views/layouts/application.html.erb」ファイルのheadタグ内で直接CDNのスクリプトを読み込ませます。


記述追加 「app/views/layouts/application.html.erb」26行目

    <!-- JQuery 3.7.1 -->
    <script
    src="https://code.jquery.com/jquery-3.7.1.min.js"
    integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
    crossorigin="anonymous"></script>

    <!-- ratyjs 3.1.1 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/raty/3.1.1/jquery.raty.min.js" integrity="sha512-Isj3SyFm+B8u/cErwzYj2iEgBorGyWqdFVb934Y+jajNg9kiYQQc9pbmiIgq/bDcar9ijmw4W+bd72UK/tzcsA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>



記述追加 【app/views/layouts/application.html.erb】26行目

<!DOCTYPE html>
<html>
  <head>
    <title>StreamAcademe</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %>

    <!-- noty -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/noty/3.1.4/noty.min.js" integrity="sha512-lOrm9FgT1LKOJRUXF3tp6QaMorJftUjowOWiDcG5GFZ/q7ukof19V0HKx/GWzXCdt9zYju3/KhBNdCLzK8b90Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

    <!-- Google Fonts -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Kaisei+Opti&family=Kosugi+Maru&family=Rampart+One&display=swap" rel="stylesheet">

    <!-- Font Awesome -->
    <script src="https://kit.fontawesome.com/dd8c589546.js" crossorigin="anonymous"></script>

    <!-- Dropzone5.5.1 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.js" integrity="sha512-jytq61HY3/eCNwWirBhRofDxujTCMFEiQeTe+kHR4eYLNTXrUq7kY2qQDKOUnsVAKN5XGBJjQ3TvNkIkW/itGw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

    <!-- JQuery 3.7.1 -->
    <script
    src="https://code.jquery.com/jquery-3.7.1.min.js"
    integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
    crossorigin="anonymous"></script>

    <!-- ratyjs 3.1.1 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/raty/3.1.1/jquery.raty.min.js" integrity="sha512-Isj3SyFm+B8u/cErwzYj2iEgBorGyWqdFVb934Y+jajNg9kiYQQc9pbmiIgq/bDcar9ijmw4W+bd72UK/tzcsA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>


  </head>

  <body>

    <!-- ナビゲーションバー -->
    <%= render  "shared/navbar" %>

    <!-- noty -->
    <%= render 'shared/notification' %>

    <%= yield %>
    
  </body>
</html>


モデル



レビューモデルを作成します。


コマンド
一文です。
rails g model Review review:text stars:bigint project:references user:references


「db\migrate\20200710011458_create_reviews.rb」ファイルを以下のように更新します。


記述更新 db\migrate\20200710011458_create_reviews.rb
5行目に「, default: 1」の記述を追加しています。

class CreateReviews < ActiveRecord::Migration[7.1]
  def change
    create_table :reviews do |t|
      t.text :review
      t.bigint :stars, default: 1
      t.references :project, null: false, foreign_key: true
      t.references :user, null: false, foreign_key: true

      t.timestamps
    end
  end
end



コマンド マイグレーション適用
rails db:migrate


「app\models\user.rb」ファイルに以下の記述を追加します。


app\models\user.rb(6行目)

has_many :reviews



app\models\user.rb

class User < ApplicationRecord

  has_many :projects
  has_many :subscriptions
  has_many :projects, through: :subscriptions
  has_many :reviews

  has_one_attached :avatar

  validates :full_name, presence: true, length: {maximum: 50}
  
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
          :confirmable, :omniauthable

  def self.from_omniauth(auth)
    user = User.where(email: auth.info.email).first

    if user
      return user
    else
      where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
        user.email = auth.info.email
        user.password = Devise.friendly_token[0, 20]
        user.full_name = auth.info.name   # ユーザーモデルに名前があると仮定
        user.image = auth.info.image # ユーザーモデルに画像があると仮定

        user.uid = auth.uid
        user.provider = auth.provider

      end
    end
  end
end



「app\models\project.rb」ファイルに以下の記述を追加します。


1.記述追加 app\models\project.rb(7行目)

has_many :reviews



2.記述追加 app\models\project.rb(16行目)

  def average_rating
    reviews.count == 0 ? 0 : reviews.average(:stars).round(1)
  end



app\models\project.rb

class Project < ApplicationRecord

  belongs_to :user
  has_many :tasks
  has_many :subscriptions
  has_many :users, through: :subscriptions
  has_many :reviews

  has_rich_text :description
  has_many_attached :images

  validates :name, presence: true, length: { maximum: 50 }
  validates :description, presence: true, length: { maximum: 1000 }
  validates :price, presence: true, numericality: { only_integer: true }

  def average_rating
    reviews.count == 0 ? 0 : reviews.average(:stars).round(1)
  end
  
end


コントローラ



レビューコントローラーを作成します。
「app\controllers」フォルダに「reviews_controller.rb」ファイルを新規作成して下さい。


app\controllers\reviews_controller.rb(新規作成したファイル)

class ReviewsController < ApplicationController
	def create
		if Review.exists?(project_id: review_params[:project_id], user_id: current_user.id)
			flash[:alert] = "レビュー済みです。"
		else
			@review = Review.create(review_params)
			project = @review.project
			if @review.save
				flash[:notice] = "レビューを投稿しました。"
			else
				flash[:alert] = "レビューできません"
			end
		
		end
		redirect_to request.referrer
	end
    
	def destroy
		@review = Review.find(params[:id])
		project = @review.project
		@review.destroy
		flash[:alert] = "レビューを削除しました。"
		redirect_to project
    end
    
    private
    
    def review_params
        params.require(:review).permit(:stars, :review, :project_id, :user_id)
    end
    
end



「app\controllers\projects_controller.rb」ファイルに以下の記述を追加します。


記述追加 app\controllers\projects_controller.rb(49行目)

    @review = Review.new
    @reviews = @project.reviews.order('created_at desc')

    @hasReview = @reviews.find_by(user_id: current_user.id) if current_user



app\controllers\projects_controller.rb

class ProjectsController < ApplicationController

  protect_from_forgery except: [:upload_photo]
  before_action :authenticate_user!, except: [:show], only: [:list]
  before_action :set_project, except: [:new, :create, :show, :index, :list]
  before_action :is_authorised, only: [:naming, :pricing, :description, :photo_upload, :update]

  def index
  	@projects = Project.all
  end

  def new
    @project = current_user.projects.build
  end

  def create
    @project = current_user.projects.build(project_params)
    if @project.save
      redirect_to naming_project_path(@project), notice: "保存しました"
    else
      redirect_to request.referrer, flash: { error: @project.errors.full_messages }
    end
  end

  def update
    new_params = project_params
    new_params = project_params.merge(active: true) if is_ready_project

    if @project.update(new_params)
      flash[:notice] = "保存しました。"
    else
      flash[:alert] = { error: @project.errors.full_messages }
    end
    redirect_back(fallback_location: request.referer)
  end

  def show
  	@project = Project.find(params[:id])
  	@tasks = @project.tasks.order(:tag)
    @i = 0
    @images = @project.images
    @joined = false
    @users = @project.users.order('created_at desc').first(10)

    if !current_user.nil? && !current_user.projects.nil?
        @joined = current_user.projects.include?(@project)
    end
    
    @review = Review.new
    @reviews = @project.reviews.order('created_at desc')

    @hasReview = @reviews.find_by(user_id: current_user.id) if current_user   
  end

  def edit
    @project = Project.find(params[:id])
  	@tasks = @project.tasks.order(:tag)
  end

  def upload_photo
    @project.images.attach(params[:file])
    render json: { success: true }
  end

  def delete_photo
    @image = ActiveStorage::Attachment.find(params[:photo_id])
    @image.purge
    redirect_to photo_upload_project_path(@project)
  end

  def list
    if !current_user.nil?
      @projects = current_user.projects
    end
  end

  private
  def set_project
    @project = Project.find(params[:id])
  end

  def project_params
    params.require(:project).permit(:name, :content, :price, :description, :images, :active)
  end

  def is_authorised
    redirect_to root_path, alert: "権限がありません。" unless current_user.id == @project.user_id
  end
  
  def is_ready_project
    !@project.active && !@project.price.blank? && !@project.name.blank? && !@project.images.blank? && !@project.description.blank?
  end

end



「app/controllers/users_controller.rb」ファイルに以下の記述を追加します。


記述追加 app/controllers/users_controller.rb(7, 13行目)

@reviews = Review.all



app/controllers/users_controller.rb

class UsersController < ApplicationController
  
  before_action :authenticate_user!

  def dashboard
    @projects = Project.all
    @reviews = Review.all
  end

  def show
    @user = User.find(params[:id])
    @projects = Project.all
    @reviews = Review.all
  end

  def update
    @user = current_user
    if @user.update(current_user_params)
      flash[:notice] = "保存しました"
    else
      flash[:alert] = "更新できません"
    end
    redirect_to dashboard_path
  end

  def update_payment
    if !current_user.stripe_id
      customer = Stripe::Customer.create(
        email: current_user.email,
        source: params[:stripeToken]
      )
    else
      customer = Stripe::Customer.update(
        current_user.stripe_id,
        source: params[:stripeToken]
      )
    end
    if current_user.update(stripe_id: customer.id, stripe_last_4: customer.sources.data.first["last4"])
      flash[:notice] = "新しいカード情報が登録されました"
    else
      flash[:alert] = "無効なカードです"
    end
    redirect_to request.referrer
  rescue Stripe::CardError => e
    flash[:alert] = e.message
    redirect_to request.referrer
  end

  private

  def current_user_params
    params.require(:user).permit(:about, :status, :avatar)
  end

end


ルート設定



ルートの設定をします。


「config\routes.rb」ファイルに以下の記述を追加します。


1.記述追加 config\routes.rb(17行目)

 post '/reviews', to: 'reviews#create'

2.記述追加 config\routes.rb(46行目)

resources :reviews, only: [:create, :destroy]



config\routes.rb

Rails.application.routes.draw do

  # ルートを app\views\pages\home.html.erb に設定
  root 'pages#home'

  # get
  get 'pages/home'
  get '/dashboard', to: 'users#dashboard'
  get '/users/:id', to: 'users#show', as: 'user'
  get '/myprojects', to: 'projects#list'
  get 'settings/payment', to: 'users#payment', as: 'settings_payment'

  # post
  post '/users/edit', to: 'users#update'
  post '/free', to: 'charges#free'
  post '/settings/payment', to: 'users#update_payment', as: "update_payment"
  post '/reviews', to: 'reviews#create'

  # device
  devise_for :users, 
    path: '', 
    path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'},
    controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'}

  resources :projects do
    member do
      get 'naming'
      get 'pricing'
      get 'description'
      get 'photo_upload'
      delete :delete_photo
      post :upload_photo
    end
    resources :tasks, only: [:show, :index]
  end

  resources :tasks, except: [:edit] do
    member do
      get 'naming'
      get 'description'
      get 'video'
      get 'code'
    end
  end

  resources :reviews, only: [:create, :destroy]

  # 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


ビューを作成します。



「app/views」フォルダに「reviews」フォルダを新規作成します。
作成した「reviews」フォルダに「_form.html.erb」ファイルを新規作成します。



新規作成 【app/views/reviews/_form.html.erb】

<!-- Button trigger modal -->
<button type="button" class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#exampleModal<%= @project.id %>">
  <font style="font-size: 0.9rem;">レビュー</font>
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal<%= @project.id %>" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
    <%= form_for Review.new do |f| %>
      <div class="modal-header">
        <h1 class="modal-title fs-5" id="exampleModalLabel"><div id="stars_<%= @project.id %>"></div></h1>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <%= f.text_area :review, class: "textarea", required: true, style: "width: 20rem; height: 10rem; margin-top: -1rem;" %>
        <%= f.hidden_field :project_id, value: @project.id %>
        <%= f.hidden_field :user_id, value: current_user.id %>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">閉じる</button>
        <%= f.submit "レビューを投稿する", class: "btn btn-warning" %>
      </div>
    <% end %>
    </div>
  </div>
</div>


<script>
    $('#stars_<%= @project.id %>').raty({
        path: '/assets',
        scoreName: 'review[stars]',
        score: 1
    });
</script>



プロジェクトを購入した生徒がレビューできるようにボタンを実装します。
「app/views/projects/show.html.erb」ファイルに以下の記述を追加します。


記述追加 app/views/projects/show.html.erb(33行目)

<div class="mt-4">
    <%= render partial: "reviews/form" %>
</div>



app/views/projects/show.html.erb

<div class="container">
    <div class="row">
        <div class="col-md-4">
            <div class="card mt-4">
                <div class="card-body">
                    <span class="badge bg-<% if @project.price != 0 %>danger<% else %>success<% end %> fs-6"><%= @project.price == 0? "無料" : "有料" %></span>
                    <h4 class="font2"><%= @project.name %></h4>
                    <div><strong>タスク数: <i class="far fa-clock"></i> <%= @tasks.count %></strong></div>

                    <div class="mt-2">
                        <%= link_to user_path(@project.user), style: "text-decoration:none;" do %>
                            <%= image_tag avatar_url(@project.user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 50px;" %>
                            <span class="font2 text-dark h4"><%= @project.user.full_name %></span>
                        <% end %>
                    </div>                    

                    <div class="mt-4">
                        <% if user_signed_in? %>

                            <!-- サブスクリプション -->
                            <% if !@joined %>

                                <%= form_tag free_path do %>
                                    <%= hidden_field_tag 'project_id', @project.id %>

                                    <button type="submit" class="btn btn-danger w-100">購入する (<%= number_to_currency(@project.price) %>)</button>
                                <% end %>

                            <% else %>
                                <div>
                                    <span class="badge bg-success fs-4">購入済みです</span>
                                </div>
                                <div class="mt-4">
                                    <%= render partial: "reviews/form" %>
                                </div>
                            <% end %>

                        <% else %>
                            <button class="btn btn-danger w-100" disabled>ログインして下さい</button>  
                        <% end %>

                    </div>                 
                </div>
            </div>
        </div>
        <div class="col-md-8">
 
            <div class="card mt-4 mb-4">
                <div class="card-body">
                    <h3 class="font1"><%= @project.name %></h3>
                    <div class="font2">
                        <%= @project.description %>
                    </div>
                    <div class="badge bg-danger fs-5 mb-4 mt-2"><%= number_to_currency(@project.price) %></div>

                    <% if @joined %>
                        <div class="alert alert-success font2 fs-5">下記のリンクからタスクを見ることができます。</div>
                        <div class="list-group mt-2">
                            <% @tasks.each do |task| %>
                                <% if task.header %>
                                    <div class="list-group-item list-group-item-action fs-6 mt-2 bg-dark text-light"><%= task.title %></div>
                                <% else %>
                                    <%= link_to [task.project, task], style: "text-decoration:none;", data: { turbo: false} do %>
                                        <div class="list-group-item list-group-item-action ml-2 fs-5"><%= task.title %></div>
                                    <% end %>
                                <% end %>
                            <% end %>
                        </div>
                    <% else %>
                        <div class="alert alert-danger font2 fs-5">購入するとタスクを見ることができます。</div>
                        <div class="list-group mt-2">
                            <% @tasks.each do |task| %>
                                <% if task.header %>
                                    <div class="list-group-item list-group-item-action fs-6 mt-2 bg-dark text-light"><%= task.title %></div>
                                <% else %>
                                    <div class="list-group-item list-group-item-action ml-2 fs-5"><%= task.title %></div>
                                <% end %>
                            <% end %>
                        </div>                    

                    <% end %>

                </div>
            </div>

        <!-- カルーセル表示 -->
        <div class="card">
            <div class="card-body">
                <div id="carouselExampleIndicators" class="carousel slide" data-bs-ride="carousel">
                    <div class="carousel-indicators">
                        <% @images.each do |image| %>
                            <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="<%= @i %>" class="<%= 'active' if image.id == @images[0].id %>" aria-current="true" aria-label="Slide <%= @i+1 %>"></button>
                            <% @i = @i +1 %>
                        <% end %>
                    </div>
                    <div class="carousel-inner">
                        <%  @project.images.each do |image| %>
                            <div class="carousel-item <%= 'active' if image.id == @images[0].id %>">
                                <%= image_tag url_for(image), class: "d-block w-100", style: "border-radius: 10px;" %>
                            </div>
                        <% end %>
                    </div>
                    <button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="prev">
                        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                        <span class="visually-hidden">Previous</span>
                    </button>
                    <button class="carousel-control-next" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="next">
                        <span class="carousel-control-next-icon" aria-hidden="true"></span>
                        <span class="visually-hidden">Next</span>
                    </button>
                </div>
            </div>
        </div>
    </div>
</div>



ブラウザ確認
http://localhost:3000/projects/3


ステータスが「完了」になると「レビューする」ボタンが表示されます。
レビューを投稿して確認します。

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



「app/views/reviews」フォルダに「_list.html.erb」ファイルを新規作成します。
作成した「_list.html.erb」ファイルを以下のように編集します。



新規作成 【app/views/reviews/_list.html.erb】

<% @reviews.each do |r| %>
    <div style="border: solid 1px #c0c0c0; margin-bottom: 0.3rem; border-radius: 5px;">
    <ul class="list-group list-group-horizontal">
        <li class="list-group-item bn" style="border:none;">
            <figure class="figure">
            <%= image_tag avatar_url(r.user), style: "width: 40px; position:relative; left: 1.3rem;", class: "figure-img img-fluid rounded-pill" %>
                <figcaption class="figure-caption">
                        <div class="font2"><%= r.user.full_name %></div>
                        <span><i class="fa fa-star" style="color: gold;"></i></span><span><%= r.stars %></span>
                </figcaption>
            </figure>
        </li>
        <li class="list-group-item bn" style="width: 80%; border:none">
            <span class="font2"><%= r.review %></span>
            <span class="text-secondary font2"><small><%= time_ago_in_words(r.created_at) %></small></span>
        </li>

        <% if (user_signed_in?) %>
            <% if current_user && current_user == r.user %>
            <li class="list-group-item bn" style="border:none;">
                <div>
                    <%= link_to r, data: { turbo_method: :delete, turbo_confirm: "コメントを削除してもよろしいですか?" }, class: "btn btn-light" do %>
                        <i class="fas fa-trash-alt" style="color: red;"></i>
                    <% end %>
                </div>
            </li>
            <% end %>
        <% end %>
                 
    </ul>
    </div>
    <% end %>



「app\views\users\show.html.erb」ファイルに以下の記述を追加します。


記述追加 app\views\users\show.html.erb
1.63行目に記述追加しています。

<%= render "reviews/list" %>



2.42行目に記述追加しています。

<span class="star-review">
           <i class="fa fa-star text-warning"></i>
           <%= project.average_rating %>
           <span class="has-text-primary">(<%= project.reviews.count %>)</span>
</span>     



app\views\users\show.html.erb

<div class="container mt-4 mb-4">
    <div class="row">
        <!-- 左側 -->
        <div class="col-md-4 mb-4">
            <div class="card">
                <div class="card-body">

                    <!-- ステータス -->
                    <div>
                        <% if @user.status %>
                            <span class="badge bg-success"><i class="fa-regular fa-bell"></i>オンライン</span>
                        <% else %>
                            <span class="btn btn-secondary"><i class="fa-regular fa-bell-slash"></i>オフライン</span>
                        <% end %>                                   
                    </div>                
                    <!-- アバター -->
                    <%= image_tag avatar_url(@user), class: "img-fluid img-thumbnail rounded-pill" %>
                    <h4 class="text-center"><%= @user.full_name %></h4>   
                    
                    <!-- 自己紹介 -->
                    <div class="h5 text-center"><%= @user.about %></div>                           
                </div>
            </div>       

        </div>
        <!-- 右側 -->
        <div class="col-md-8">

            <!-- 登録しているプロジェクト -->
            <div class="card mb-4">           
                <div class="card-body">
                    <h5 class="card-title"><%= @user.full_name %>さんが登録しているプロジェクト</h5>
                    <div class="row">
                        <% @projects.each do |project| %>
                            <% if project.active? && project.user == @user %>
                                <div class="col-md-4">
                                    <div class="card mb-2">
                                        <%= link_to project_path(project), data: { turbo: false} do %>
                                            <%= image_tag project_cover(project), style: "width: 100%;", class: "card-img-top" %>
                                        <% end %>                                    
                                        <div class="card-body">
                                            <span class="star-review">
                                                <i class="fa fa-star text-warning"></i>
                                                <%= project.average_rating %>
                                                <span class="has-text-primary">(<%= project.reviews.count %>)</span>
                                            </span>           

                                            <%= link_to project_path(project), data: { turbo: false} do %>
                                                <h5 class="card-title">
                                                    <span class="btn btn-light"><%= project.name %></span>
                                                </h5>
                                            <% end %>
                                            <div class="badge bg-danger fs-5 mb-4 mt-2"><%= number_to_currency(project.price) %></div>                        
                                        </div>
                                    </div>
                                </div>
                            <% end %>
                        <% end %>
                    </div>

                </div>
            </div>

            <!-- レビュー -->
            <div class="card">           
                <div class="card-body">
                    <h5 class="card-title"><%= @user.full_name %>さんへのレビュー</h5>
                    <%= render "reviews/list" %>
                </div>
            </div>
        </div>     
    </div>
</div>



ブラウザ確認
http://localhost:3000/users/2

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



ダッシュボードを修正してレビューのスターを反映させます。
合わせてレビュー表示も行います。


記述追加 app\views\users\dashboard.html.erb(195行目)
1.97行目に以下の記述を追加します。

<span class="star-review">
      <i class="fa fa-star text-warning"></i>
      <%= project.average_rating %>
      <span class="has-text-primary">(<%= project.reviews.count %>)</span>
</span>   



2.119行目に以下の記述を追加します。

           <!-- レビュー -->
            <div class="card mb-2 mt-2">           
                <div class="card-body">
                    <h5 class="card-title font1">投稿したレビュー</h5>
                    <%= render "reviews/list" %>
                </div>
            </div>  



app\views\users\dashboard.html.erb

<div class="container mt-4 mb-4">
    <div class="row">
        <!-- 左側 -->
        <div class="col-md-4">
            <div class="card">
                <div class="card-body">
                    <!-- アバター -->
                    <%= image_tag avatar_url(current_user), class: "img-fluid img-thumbnail rounded-pill" %>
                    <h4 style="margin-left: 5.5rem;"><%= current_user.full_name %></h4>
                    <!-- 画像アップロードボタン -->
                    <button class="btn btn-dark text-light w-100" type="button" data-bs-toggle="collapse" data-bs-target="#collapse1" aria-expanded="false" aria-controls="collapse1">
                        <i class="fa-solid fa-cloud-arrow-up"></i>アバター画像アップロード
                    </button>
                    <div class="collapse" id="collapse1">
                        <div class="card card-body">
                            <%= form_for :user, url: users_edit_url(current_user), action: :update, method: :post do |f| %>
                                <%= f.file_field :avatar, class: "input-group-text", onchange: "this.form.submit();" %>
                            <% end %>   
                        </div>
                    </div>
                    <hr/>
                    登録:<%= I18n.l(current_user.created_at, format: :full_date) %>
                    <hr/>
                    <div type="button" data-bs-toggle="collapse" data-bs-target="#collapse2" aria-expanded="false" aria-controls="collapse2">

                        <% if current_user.status %>
                            <span class="btn btn-success"><i class="toggle far fa-edit"></i>オンライン</span>
                        <% else %>
                            <span class="btn btn-secondary"><i class="toggle far fa-edit"></i>オフライン</span>
                        <% end %>                
                    
                    </div>
                    <div class="collapse" id="collapse2">
                        <div class="card card-body">

                            <%= form_for :user, url: users_edit_url(current_user), action: :update, method: :post do |f| %>
                                <%= f.select(:status, options_for_select([["オンライン", true], ["オフライン", false]]), {}, {class: "custom-select"}) %>                        
                                <%= f.submit "保存", class: "btn btn-dark" %>
                            <% end %>

                        </div>
                    </div>
                    <hr/>
                    <div class="h5"><%= current_user.about %></div>
                    <button class="btn btn-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#collapse3" aria-expanded="false" aria-controls="collapse3">
                        自己紹介編集
                    </button>

                    <div class="collapse" id="collapse3">
                        <div class="card card-body">
                            <%= form_for :user, url: users_edit_url(current_user), action: :update, method: :post do |f| %>
                                <div><%= f.text_area :about, autofocus: true, autocomplete: 'form'%></div>
                                <%= f.submit "保存", class: "btn btn-dark" %>
                            <% end %>                        
                        </div>
                    </div>                
                    <hr/>
                    <!-- 電話番号 -->
                    <div>
                        <% if !current_user.phone_number.blank? %>
                            <span class="pull-right icon-babu"><i class="far fa-check-circle" style="color:green;"></i></span>&nbsp;&nbsp;電話番号
                        <% else %>
                            <div class="text-danger">電話番号が登録されていません</div>
                            <%= link_to  "電話番号登録", edit_user_registration_path, class: "btn btn-danger" %>
                        <% end %>                    
                    </div>                              
                </div>
            </div>
        </div>
        <!-- 右側 -->
        <div class="col-md-8">

            <!-- お知らせ -->
            <div class="card mb-2">
                <div class="card-body">
                    <h5 class="card-title">お知らせ</h5>
                    <h6 class="card-subtitle mb-2 text-body-secondary">
                    </h6>
                    <p class="card-text">
                    </p>    
                </div>
            </div>

            <!-- 登録しているプロジェクト -->
            <div class="card">
                <div class="card-body">
                    <h5 class="card-title">登録しているプロジェクト</h5>
                    <div class="row">
                        <% @projects.each do |project| %>
                            <% if project.active? && project.user == current_user %>
                                <div class="col-md-4">
                                    <div class="card mb-2">
                                        <%= link_to project_path(project), data: { turbo: false} do %>
                                            <%= image_tag project_cover(project), style: "width: 100%;", class: "card-img-top" %>
                                        <% end %>                                    
                                        <div class="card-body">    
                                            <span class="star-review">
                                                <i class="fa fa-star text-warning"></i>
                                                <%= project.average_rating %>
                                                <span class="has-text-primary">(<%= project.reviews.count %>)</span>
                                            </span>      
                                            <%= link_to project_path(project), data: { turbo: false} do %>
                                                <h5 class="card-title">
                                                    <span class="btn btn-light"><%= project.name %></span>
                                                </h5>
                                            <% end %>
                                            <div class="badge bg-danger fs-5 mb-4 mt-2"><%= number_to_currency(project.price) %></div>
                                            <%= link_to edit_project_path(project), class: "btn btn-outline-primary w-100 mb-4" do %>
                                                登録内容編集
                                            <% end %>                         
                                        </div>
                                    </div>
                                </div>
                            <% end %>
                        <% end %>
                    </div>
                </div>
            </div>
            <!-- レビュー -->
            <div class="card mb-2 mt-2">           
                <div class="card-body">
                    <h5 class="card-title font1">レビュー</h5>
                    <%= render "reviews/list" %>
                </div>
            </div>  
        </div>     
    </div>
</div>



ブラウザ確認
http://localhost:3000/dashboard

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



33 | クレジットカード決済の実装】 << 【ホーム】 >> 【35 | ホームページ




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