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

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

Rails6.1 | 仕事売買アプリ作成 | 33 | Offer

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



32 | Request】 << 【ホーム】 >> 【34 | Action



フリーランサー(仕事をする人)がクライアント(仕事を頼む人)が出したリクエストに申し込み出来るようにします。

モデル



オファーモデルを作成します。


コマンド
一文です。
rails g model Offer note:text amount:bigint days:bigint status:bigint request:references user:references


「db\migrate\20200527004950_create_offers.rb」ファイルを以下のように編集します。


記述編集 db\migrate\20200527004950_create_offers.rb
7行目に「, default: 0」の記述を追加しています。

class CreateOffers < ActiveRecord::Migration[6.1]
  def change
    create_table :offers do |t|
      t.text :note
      t.bigint :amount
      t.bigint :days
      t.bigint :status, default: 0
      t.references :request, null: false, foreign_key: true
      t.references :user, null: false, foreign_key: true

      t.timestamps
    end
  end
end



マイグレーションを適用します。
コマンド マイグレーション適用
rails db:migrate


「app\models\offer.rb」ファイルを以下のように編集します。


記述編集 app\models\offer.rb

class Offer < ApplicationRecord
  belongs_to :request
  belongs_to :user

  enum status: [:pending, :accepted, :rejected]
  validates :amount, :days, numericality: { only_integer: true, message: "数字でなければなりません" }
end



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


記述追加 app\models\user.rb(5行目)

has_many :offers



app\models\user.rb

class User < ApplicationRecord

  has_many :gigs
  has_many :requests
  has_many :offers
  has_many :buying_orders, foreign_key: "buyer_id", class_name: "Order"
  has_many :selling_orders, foreign_key: "seller_id", class_name: "Order"

  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\request.rb」ファイルに以下の記述を追加します。


記述追加 app\models\request.rb(5行目)

has_many :offers, dependent: :delete_all



app\models\request.rb

class Request < ApplicationRecord
  belongs_to :user
  belongs_to :category

  has_many :offers, dependent: :delete_all

  has_one_attached :attachment_file

  validates :title, presence: { message: "空白にはできません" }
  validates :description, presence: { message: "空白にはできません" }
  validates :delivery, numericality: { only_integer: true, message: "数字でなければなりません" }
end


コントローラー



オファーコントローラを作成します。


「app\controllers」フォルダに「offers_controller.rb」ファイルを新規作成して下さい。


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

class OffersController < ApplicationController
    before_action :authenticate_user!
    before_action :set_offer, only: [:accept, :reject]
    before_action :is_authorised, only: [:accept, :reject]

    def create
        req = Request.find(offer_params[:request_id])

        if req && req.user_id == current_user.id
            redirect_to request.referrer, alert: "自分のリクエストに申し込みはできません。"
        
        elsif Offer.exists?(user_id: current_user.id, request_id: offer_params[:request_id])
            redirect_to request.referrer, alert: "申し込みできるのは1回だけです"
        
        else
            @offer = current_user.offers.build(offer_params)
            if @offer.save
                redirect_to request.referrer, notice: "保存しました"
                
            else
                redirect_to request.referrer, flash: {error: @offer.errors.full_messages.join(', ')}
            end
        end
    end

    def accept

    end

    def reject

    end

    private

    def set_offer
        @offer = Offer.find(params[:id])
    end

    def is_authorised
        redirect_to root_path, alert: "権限がありません。" unless current_user.id == @offer.request.user_id
    end

    def offer_params
        params.require(:offer).permit(:amount, :days, :note, :request_id, :status)
    end
end



リクエストの確認でも申し込み数を表示できるようにします。


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


記述追加 app\controllers\requests_controller.rb(54行目)

  def offers
    @offers = @request.offers
  end



app\controllers\requests_controller.rb

class RequestsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_request, except: [:new, :create, :index, :list]
  before_action :is_authorised, only: [:edit, :update, :destroy]
  before_action :set_categories, only: [:new, :edit, :list]
 

  def index
    @requests = current_user.requests
  end

  def new
    @request = current_user.requests.build
  end

  def create
    @request = current_user.requests.build(request_params)
    if @request.save
      redirect_to requests_path, notice: "保存しました"
    else
      redirect_to request.referrer, flash: {error: @request.errors.full_messages.join(', ')}
    end
  end

  def edit
  end

  def update
    if @request.update(request_params)
      redirect_to requests_path, notice: "保存しました"
    else
      redirect_to request.referrer, flash: {error: @request.errors.full_messages.join(', ')}
    end
  end

  def show
  end

  def destroy
    @request.destroy
    redirect_to requests_path, notice: "削除しました"
  end

  def list
    @category_id = params[:category]

    if @category_id.present?
      @requests = Request.where(category_id: @category_id)
    else
      @requests = Request.all
    end
  end

  def offers
    @offers = @request.offers
  end

  private
  def set_categories
    @categories = Category.all
  end

  def set_request
    @request = Request.find(params[:id])
  end

  def is_authorised
    redirect_to root_path, alert: "あなたに権限はありません。" unless current_user.id == @request.user_id
  end

  def request_params
    params.require(:request).permit(:description, :category_id, :delivery, :budget, :attachment_file, :title)
  end
end


ルート設定



ルートを設定します。


記述追加 config\routes.rb
13行目に「get '/request_offers/:id', to: 'requests#offers', as: 'request_offers'」の記述を追加します。
17行目に「post '/offers', to: 'offers#create'」の記述を追加しています。

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 '/selling_orders', to: 'orders#selling_orders'
  get '/buying_orders', to: 'orders#buying_orders'
  get '/all_requests', to: 'requests#list'
  get '/request_offers/:id', to: 'requests#offers', as: 'request_offers'

  # post
  post '/users/edit', to: 'users#update'
  post '/offers', to: 'offers#create'

  put '/orders/:id/complete', to: 'orders#complete', as: 'complete_order'

  resources :gigs do
    member do
      delete :delete_photo
      post :upload_photo
    end
    resources :orders, only: [:create]
  end

  resources :requests

  # 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'}
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end


ビュー



リクエスト詳細ビューに申し込みボタンを追加します。
「app\views\requests\show.html.erb」ファイルに以下の記述を追加します。


記述追加 app\views\requests\show.html.erb(5行目)

            <div class="card mb-2">
                <div class="card-body">
                    <h5 class="card-title font1">リクエストに申し込む</h5>
                    <%= form_for Offer.new do |f| %>                        
                        <%= f.hidden_field :request_id, value: @request.id %>
                        <div class="mt-4">
                            <label for="" class="label">希望価格 (円)</label>
                            <%= f.text_field :amount, class: "form-control" %>
                        </div>
                        <div class="mt-2">
                            <label for="" class="label">期日 (日)</label>
                            <%= f.text_field :days, class: "form-control" %>
                        </div>
                        <div class="mt-2">
                            <label for="" class="label">コメント</label>
                            <%= f.text_area :note, class: "form-control" %>
                        </div>
                        <div class="mt-4">
                        <%= f.submit '申し込む', class: "btn btn-danger w-100" %>
                        </div>                                
                    <% end %>
                </div>
            </div>        



app\views\requests\show.html.erb

<div class="container mt-4">
    <div class="row">
        <!-- 左側 -->
        <div class="col-md-4">
            <div class="card mb-2">
                <div class="card-body">
                    <h5 class="card-title font1">リクエストに申し込む</h5>
                    <%= form_for Offer.new do |f| %>                        
                        <%= f.hidden_field :request_id, value: @request.id %>
                        <div class="mt-4">
                            <label for="" class="label">希望価格 (円)</label>
                            <%= f.text_field :amount, class: "form-control" %>
                        </div>
                        <div class="mt-2">
                            <label for="" class="label">期日 (日)</label>
                            <%= f.text_field :days, class: "form-control" %>
                        </div>
                        <div class="mt-2">
                            <label for="" class="label">コメント</label>
                            <%= f.text_area :note, class: "form-control" %>
                        </div>
                        <div class="mt-4">
                        <%= f.submit '申し込む', class: "btn btn-danger w-100" %>
                        </div>                                
                    <% end %>
                </div>
            </div>        
        </div>

        <!-- 右側 -->
        <div class="col-md-8">
            <div class="card">
                <div class="card-body">
                    <!-- タイトル -->
                    <div class="card-title">
                        <h3 class="font1"><%= @request.title %></h3>
                        <div class="mt-4">
                            <div class="mt-4">
                                <span class="font1">期日:</span><%= @request.delivery %>日 | <span class="font1">申し込み:</span> 0 | <span class="font1">予算:</span> <%= number_to_currency(@request.budget) %>
                            </div>
                        </div>

                        <!-- 内容 -->
                        <div class="card">
                            <div class="card-body">

                            <div>
                                <span class="font1">カテゴリー:</span><%= @request.category.name %>
                            </div>
                            <div>
                                <span class="font1">リクエスト日:</span><%= I18n.l(@request.created_at, format: :full_date) %>
                            </div>

                            <h6 class="font1 mt-4">クライアント</h6>
                            <div class="mt-2">
                                <%= link_to user_path(@request.user), style: "text-decoration:none;" do %>
                                    <%= image_tag avatar_url(@request.user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 80px;" %>
                                    <span class="font2 text-dark h4"><%= @request.user.full_name %></span>
                                <% end %>
                            </div>

                            <div class="card-title mt-4"><h4 class="font1">内容</strong></h4>
                                <div class="mt-4">
                                    <span class="font2"><%= @request.description %></span>
                                </div>
                                <% if @request.attachment_file.attached? %>
                                    <div class="mt-4 mb-4">
                                        <%= link_to url_for(@request.attachment_file), 
                                            class: "badge bg-success",  
                                            download: "Attachment_#{@request.attachment_file.id}",
                                            style: "text-decoration: none;" do %>

                                                <i class="fas fa-paperclip fa-lg p-r-5"></i><span class="fs-6"><%= @request.attachment_file.filename %></span>
                                        <% end %>
                                    </div>
                                <% end %>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>



実際にリクエストにオファーできるか動作を確認してください。
ブラウザ確認
http://localhost:3000/requests/1

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


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



申し込みを受けたオファーの一覧表示を実装します。
「app\views\request」フォルダに「offers.html.erb」ファイルを新規作成します。


app\views\requests\offers.html.erb(新規作成したファイル)

<div class="container">
    <div class="card mb-2 mt-2">
        <div class="card-body">
            <% @offers.each do |o| %>
                <ul class="list-group mt-4">
                    <li class="list-group-item" style="border: none;">
                        <span class="font1">リクエスト名:</span>
                        <%= o.request.title %>
                    </li>
                    <li class="list-group-item" style="border: none;">
                        <span class="font1">申し込み日:</span><%= I18n.l(o.created_at, format: :full_date) %>
                    </li>
                    <li class="list-group-item" style="border: none;">
                        <span class="font1">フリーランサー</span>                            
                        <%= link_to user_path(o.user), style: "text-decoration:none;" do %>
                            <%= image_tag avatar_url(o.user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 50px;" %>
                            <span class="font2 text-dark h4"><%= o.user.full_name %></span>
                        <% end %>            
                    </li>   
                    <li class="list-group-item" style="border: none;">
                        <span class="font1">コメント:</span> <%= o.note %>        
                    </li>                         
                    <li class="list-group-item" style="border: none;">
                        <span class="font1">期日:</span> <%= o.days %></li>
                    <li class="list-group-item" style="border: none;">
                        <span class="font1">価格:</span><%= number_to_currency(o.amount) %>
                    </li>                                            
                </ul>
            <% end %>
        </div>
    </div>
</div>



表示を確認します。
リンクに渡すパラメーターはオファーのIDではなく、オファーをしたリクエストのIDです。
ブラウザ確認
http://localhost:3000/request_offers/5

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


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



ダッシュボードの登録リクエスト一覧にオファーがあった時にオファーの一覧を表示できるよう、リンクを追加します。
「app/views/users/dashboard.html.erb」ファイルに以下の記述を追加します。

<div>
     <% if r.offers.count == 0 %>
           <span class="badge bg-secondary">まだオファーがありません</span>
    <% else %>
          <%= link_to request_offers_path(r) do %>
                 <span class="badge bg-danger"><%= r.offers.count %>件のオファーが入りました</span>
          <% end %>
   <% end %>                                    
</div>



記述追加 【app/views/users/dashboard.html.erb】130行目

<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">
                <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 mt-2">
                <div class="card-body">
                    <h5 class="card-title">登録している仕事</h5>

                    <div class="row">
                        <% current_user.gigs.each do |gig| %>
                            <% if gig.active? %>
                                <div class="col-md-4">
                                    <div class="card mb-2">
                                    <%= link_to gig_path(gig), data: { turbolinks: false} do %>
                                        <%= image_tag gig_cover(gig), style: "width: 100%;", class: "card-img-top" %>
                                    <% end %>                                    
                                        <div class="card-body">
                                            <%= link_to gig_path(gig), data: { turbolinks: false} do %>
                                                <h5 class="card-title">
                                                    <span class="btn btn-light"><%= gig.title %></span>
                                                </h5>
                                            <% end %>
                                            <div class="card-text" style="margin-left: 0.5rem;">
                                                <p><%= gig.summary %></p>          
                                                <%= link_to edit_gig_path(gig), class: "btn btn-outline-primary w-100 mb-4" do %>
                                                    登録内容編集
                                                <% end %>
                                              
                                            </div>                             
                                        </div>
                                    </div>
                                </div>
                            <% end %>
                        <% end %>
                    </div>
                </div>
            </div>
            <!-- 登録リクエスト -->
            <div class="card mt-2">
                <div class="card-body">
                    <h5 class="card-title">登録しているリクエスト</h5>

                    <div class="row">
                    <% current_user.requests.each do |r| %>

                        <div class="col-md-4">
                            <div class="card mb-2">
                                <div class="card-body">
                                    <div>
                                        <% if r.offers.count == 0 %>
                                            <span class="badge bg-secondary">まだオファーがありません</span>
                                        <% else %>
                                            <%= link_to request_offers_path(r) do %>
                                                <span class="badge bg-danger"><%= r.offers.count %>件のオファーが入りました</span>
                                            <% end %>
                                        <% end %>                                    
                                    </div>
                                    <ul class="list-group mt-4">
                                        <li class="list-group-item" style="border: none;">
                                            <span class="font1">リクエスト日:</span><%= I18n.l(r.created_at, format: :full_date) %>
                                        </li>
                                        <li class="list-group-item" style="border: none;">
                                            <span class="font1">リクエスト名:</span>
                                            <%= link_to r.title, request_path(r), class: "btn btn-light" %>
                                        </li>               
                                        <li class="list-group-item" style="border: none;">
                                            <span class="font1">期日:</span>   <%= r.delivery %></li>
                                        <li class="list-group-item" style="border: none;">
                                            <span class="font1">価格:</span><%= number_to_currency(r.budget) %>
                                        </li>
                                        <% if r.attachment_file.attached? %>
                                            <div class="mt-2">
                                                <%= link_to url_for(r.attachment_file), 
                                                                class: "badge bg-success",  
                                                                download: "Attachment_#{r.attachment_file.id}",
                                                                style: "text-decoration: none;" do %>
            
                                                    <i class="fas fa-paperclip fa-lg p-r-5"></i><span class="fs-6"><%= r.attachment_file.filename %></span>
            
                                                <% end %>
                                            </div>
                                        <% end %>
                                        <li class="list-group-item mt-4" style="border: none;">
                                        <%= link_to edit_request_path(r), class: "btn btn-outline-primary w-100 mb-4" do %>
                                            登録内容編集
                                        <% end %>
                                        </li>                                      
                                    </ul>
                                </div>
                            </div>
                        </div>
                    <% end %>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>



ブラウザを確認します。
リンクをクリックすると登録したリクエストのオファー一覧が表示されます。
ブラウザ確認
http://localhost:3000/dashboard

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


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



リクエストの一覧にオファー数を追加します。
「app\views\requests\list.html.erb」ファイルを以下のように編集します。


記述編集 app\views\requests\list.html.erb(16行目)

<% if r.offers.count == 0 %>
       <span class="badge bg-secondary">まだ申し込みはありません</span>
<% else %>
       <span class="badge bg-danger"><%= r.offers.count %>件の申し込みがあります</span>
<% end %>        



app\views\requests\list.html.erb

<div class="container mt-4">
    <h4 class="font1">
        全てのリクエスト
    </h4>
    <div class="row">
        <%= form_tag '', method: :get do %>
            <%= select_tag 'category', content_tag(:option, '全てのカテゴリー', value: "") + 
                                        options_for_select(@categories.map { |c| [c.name, c.id] }, 
                                        selected: @category_id),
                                        onchange: "this.form.submit();" %>
        <% end %>
        <% @requests.each do |r| %>
            <div class="col-md-4">
                <div class="card mb-2">
                    <div class="card-body">
                        <% if r.offers.count == 0 %>
                            <span class="badge bg-secondary">まだ申し込みはありません</span>
                        <% else %>
                            <span class="badge bg-danger"><%= r.offers.count %>件の申し込みがあります</span>
                        <% end %>         
                        <ul class="list-group mt-4">
                            <li class="list-group-item" style="border: none;">
                                <span class="font1">リクエスト日:</span><%= I18n.l(r.created_at, format: :full_date) %>
                            </li>
                            <li class="list-group-item" style="border: none;">
                                <span class="font1">リクエスト名:</span>
                                <%= link_to r.title, request_path(r), class: "btn btn-light" %>
                            </li>
                            <li class="list-group-item" style="border: none;">
                                <span class="font1">クライアント</span>                            
                                <%= link_to user_path(r.user), class: "tootip", style: "text-decoration: none;" do %>
                                    <span class="btn btn-light"><%= r.user.full_name %></span>
                                <% end %>                                                                     
                            </li>                    
                            <li class="list-group-item" style="border: none;">
                                <span class="font1">期日:</span>   <%= r.delivery %></li>
                            <li class="list-group-item" style="border: none;">
                                <span class="font1">価格:</span><%= number_to_currency(r.budget) %>
                            </li>
                            <% if r.attachment_file.attached? %>
                                <div class="mt-2">
                                    <%= link_to url_for(r.attachment_file), 
                                                    class: "badge bg-success",  
                                                    download: "Attachment_#{r.attachment_file.id}",
                                                    style: "text-decoration: none;" do %>

                                        <i class="fas fa-paperclip fa-lg p-r-5"></i><span class="fs-6"><%= r.attachment_file.filename %></span>

                                    <% end %>
                                </div>
                            <% end %>                                      
                        </ul>
                    </div>
                </div>
            </div>
        <% end %>
    </div>
</div>



申込数が表示されるようになりました。
ブラウザ確認
http://localhost:3000/all_requests

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


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



リクエスト詳細ページにも申込数の表示を追加します。
「app\views\requests\show.html.erb」ファイルに以下の記述を追加します。


記述追加 app\views\requests\show.html.erb(39行目)

<span class="font1">期日:</span><%= @request.delivery %>日 | <span class="font1">申し込み:</span><%= @request.offers.count %>件 | <span class="font1">予算:</span> <%= number_to_currency(@request.budget) %>



app\views\requests\show.html.erb

<div class="container mt-4">
    <div class="row">
        <!-- 左側 -->
        <div class="col-md-4">
            <div class="card mb-2">
                <div class="card-body">
                    <h5 class="card-title font1">リクエストに申し込む</h5>
                    <%= form_for Offer.new do |f| %>                        
                        <%= f.hidden_field :request_id, value: @request.id %>
                        <div class="mt-4">
                            <label for="" class="label">希望価格 (円)</label>
                            <%= f.text_field :amount, class: "form-control" %>
                        </div>
                        <div class="mt-2">
                            <label for="" class="label">期日 (日)</label>
                            <%= f.text_field :days, class: "form-control" %>
                        </div>
                        <div class="mt-2">
                            <label for="" class="label">コメント</label>
                            <%= f.text_area :note, class: "form-control" %>
                        </div>
                        <div class="mt-4">
                        <%= f.submit '申し込む', class: "btn btn-danger w-100" %>
                        </div>                                
                    <% end %>
                </div>
            </div>        
        </div>

        <!-- 右側 -->
        <div class="col-md-8">
            <div class="card">
                <div class="card-body">
                    <!-- タイトル -->
                    <div class="card-title">
                        <h3 class="font1"><%= @request.title %></h3>
                        <div class="mt-4">
                            <div class="mt-4">
                                <span class="font1">期日:</span><%= @request.delivery %>日 | <span class="font1">申し込み:</span><%= @request.offers.count %>件 | <span class="font1">予算:</span> <%= number_to_currency(@request.budget) %>
                            </div>
                        </div>

                        <!-- 内容 -->
                        <div class="card">
                            <div class="card-body">

                            <div>
                                <span class="font1">カテゴリー:</span><%= @request.category.name %>
                            </div>
                            <div>
                                <span class="font1">リクエスト日:</span><%= I18n.l(@request.created_at, format: :full_date) %>
                            </div>

                            <h6 class="font1 mt-4">クライアント</h6>
                            <div class="mt-2">
                                <%= link_to user_path(@request.user), style: "text-decoration:none;" do %>
                                    <%= image_tag avatar_url(@request.user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 80px;" %>
                                    <span class="font2 text-dark h4"><%= @request.user.full_name %></span>
                                <% end %>
                            </div>

                            <div class="card-title mt-4"><h4 class="font1">内容</strong></h4>
                                <div class="mt-4">
                                    <span class="font2"><%= @request.description %></span>
                                </div>
                                <% if @request.attachment_file.attached? %>
                                    <div class="mt-4 mb-4">
                                        <%= link_to url_for(@request.attachment_file), 
                                            class: "badge bg-success",  
                                            download: "Attachment_#{@request.attachment_file.id}",
                                            style: "text-decoration: none;" do %>

                                                <i class="fas fa-paperclip fa-lg p-r-5"></i><span class="fs-6"><%= @request.attachment_file.filename %></span>
                                        <% end %>
                                    </div>
                                <% end %>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>



申込数が表示されるようになりました。
ブラウザ確認
http://localhost:3000/requests/5

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


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



クライアントが登録したリクエスト一覧にも申し込みを確認するリンクを追加します。
「app\views\requests\index.html.erb」ファイルに以下の記述を追加します。


記述追加 app\views\requests\index.html.erb(27行目)

<div class="mt-4 mb-2">
        <% if r.offers.count == 0 %>
                <span class="badge bg-secondary">まだオファーがありません</span>
        <% else %>
                 <%= link_to request_offers_path(r) do %>
                           <span class="badge bg-danger"><%= r.offers.count %>件のオファーが入りました</span>
                 <% end %>
        <% end %>
</div>       



app\views\requests\index.html.erb

<div class="container mt-4">
    <div class="card">
        <div class="card-body">

            <h5 class="card-title text-danger h3 font1">リクエスト一覧(クライアント)</h5>
            <div class="mt-4">
                <%= link_to '新しいリクエストを登録', new_request_path, class: "btn btn-primary"%>
            </div>
            <% if @requests.blank? %>
                <h5 class="font1">表示できるリクエストはありません。</h5>
            <% end %>

            <% @requests.each do |r| %>
                <div class="card mt-4">
                    <div class="card-body">
                        <div class="mt-2">                                    

                            <%= link_to edit_request_path(r), style: "text-decoration: none;" do %>
                                <span class="text-success">
                                    <i class="far fa-edit fa-lg"></i>編集
                                </span>
                            <% end %>

                            <%= link_to r, method: :delete, data: {confirm: "削除してよろしいですか?"}, style: "text-decoration: none;" do %>
                                <span class="text-danger">
                                    <i class="far fa-trash-alt fa-lg"></i>削除
                                </span>
                            <% end %>

                        </div>
                        <div class="mt-4 mb-2">
                            <% if r.offers.count == 0 %>
                                <span class="badge bg-secondary">まだオファーがありません</span>
                            <% else %>
                                <%= link_to request_offers_path(r) do %>
                                    <span class="badge bg-danger"><%= r.offers.count %>件のオファーが入りました</span>
                                <% end %>
                            <% end %>
                        </div>       
                        <ul class="list-group mt-4">

                            <li class="list-group-item" style="border: none;">
                                <span class="font1">リクエスト日:</span><%= I18n.l(r.created_at, format: :full_date) %>
                            </li>
                            <li class="list-group-item" style="border: none;">
                                <span class="font1">リクエスト名:</span>
                                <%= link_to r.title, request_path(r), class: "btn btn-light" %>
                            </li>
                            <li class="list-group-item" style="border: none;">
                                <span class="font1">期日:</span>   <%= r.delivery %></li>
                            <li class="list-group-item" style="border: none;">
                                <span class="font1">価格:</span><%= number_to_currency(r.budget) %>
                            </li>                  
                        </ul>

                    </div>
                </div>
            <% end %>
        </div>
    </div>
</div>



申し込みの確認ができるリンクができました。
リンクをクリックすると申込みのリストが表示されます。
ブラウザ確認
http://localhost:3000/requests

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


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



ユーザ情報ページのリクエスト一覧にもオファー数の表示を追加します。
「app/views/users/show.html.erb」ファイルに以下の記述を追加します。

<% if r.offers.count == 0 %>
      <span class="badge bg-secondary">まだ申し込みはありません</span>
<% else %>
      <span class="badge bg-danger"><%= r.offers.count %>件の申し込みがあります</span>
<% end %>     



記述追加 【app/views/users/show.html.erb】85行目

<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-2">           
                <div class="card-body">
                    <h5 class="card-title"><%= @user.full_name %>さんへのレビュー</h5>
                    <h6 class="card-subtitle mb-2 text-body-secondary">
                    </h6>
                    <p class="card-text">
                    </p>    
                </div>
            </div>     

            <!-- 登録している仕事 -->
            <div class="card mb-2">
                <div class="card-body">
                    <h5 class="card-title font1"><%= @user.full_name %>さんが登録している仕事</h5>

                    <div class="row">
                        <% @user.gigs.each do |gig| %>
                            <% if gig.active? %>
                                <div class="col-md-4">
                                    <div class="card mb-2">
                                        <%= link_to gig_path(gig), data: { turbolinks: false} do %>
                                            <%= image_tag gig_cover(gig), style: "width: 100%;", class: "card-img-top" %>
                                        <% end %>                                    
                                        <div class="card-body">
                                            <%= link_to gig_path(gig), data: { turbolinks: false} do %>
                                                <h5 class="card-title">
                                                    <span class="btn btn-light"><%= gig.title %></span>
                                                </h5>
                                                <div class="badge bg-primary">
                                                    <% if gig.has_single_pricing%>
                                                        シングルプランのみ
                                                    <% else %>
                                                        3プラン
                                                    <% end %>
                                                </div>
                                            <% end %>                        
                                        </div>
                                    </div>
                                </div>
                            <% end %>
                        <% end %>
                    </div>
                </div>  
            </div>
            <!-- 登録リクエスト -->
            <div class="card mt-2">
                <div class="card-body">
                    <h5 class="card-title font1"><%= @user.full_name %>さんが登録しているリクエスト</h5>

                    <div class="row">
                    <% @user.requests.each do |r| %>

                        <div class="col-md-4">
                            <div class="card mb-2">
                                <div class="card-body">
                                    <% if r.offers.count == 0 %>
                                        <span class="badge bg-secondary">まだ申し込みはありません</span>
                                    <% else %>
                                        <span class="badge bg-danger"><%= r.offers.count %>件の申し込みがあります</span>
                                    <% end %>     

                                    <ul class="list-group mt-4">
                                        <li class="list-group-item" style="border: none;">
                                            <span class="font1">リクエスト日:</span><%= I18n.l(r.created_at, format: :full_date) %>
                                        </li>
                                        <li class="list-group-item" style="border: none;">
                                            <span class="font1">リクエスト名:</span>
                                            <%= link_to r.title, request_path(r), class: "btn btn-light" %>
                                        </li>               
                                        <li class="list-group-item" style="border: none;">
                                            <span class="font1">期日:</span>   <%= r.delivery %></li>
                                        <li class="list-group-item" style="border: none;">
                                            <span class="font1">価格:</span><%= number_to_currency(r.budget) %>
                                        </li>
                                        <% if r.attachment_file.attached? %>
                                            <div class="mt-2">
                                                <%= link_to url_for(r.attachment_file), 
                                                                class: "badge bg-success",  
                                                                download: "Attachment_#{r.attachment_file.id}",
                                                                style: "text-decoration: none;" do %>
            
                                                    <i class="fas fa-paperclip fa-lg p-r-5"></i><span class="fs-6"><%= r.attachment_file.filename %></span>
            
                                                <% end %>
                                            </div>
                                        <% end %>                         
                                    </ul>
                                </div>
                            </div>
                        </div>
                    <% end %>
                </div>
            </div>
        </div>
    </div>
</div>



ブラウザを確認します。
http://localhost:3000/users/3

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


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



32 | Request】 << 【ホーム】 >> 【34 | Action


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