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

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

Rails6.0 | 仕事売買サイトの構築 | 30 | 仕事を受ける

[29]申し込み << [ホームに戻る] >> [31]仕事完了


申込みの確認が出来るようにします。


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


1.記述追加 app\controllers\requests_controller.rb(4,5行目)
4行目の最後に「, :my_offers」の記述を追加します。
5行目の最後に「, :offers」の記述を追加しています。

  before_action :set_request, except: [:new, :create, :index, :list, :my_offers]
  before_action :is_authorised, only: [:edit, :update, :destroy, :offers]



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

  def my_offers
    @offers = current_user.offers
  end



app\controllers\requests_controller.rb

class RequestsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_request, except: [:new, :create, :index, :list, :my_offers]
  before_action :is_authorised, only: [:edit, :update, :destroy, :offers]
  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

  def my_offers
    @offers = current_user.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
18行目に「get '/my_offers', to: 'requests#my_offers'」の記述を追加しています。

Rails.application.routes.draw do

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

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

  get 'pages/home'
  get '/dashboard', to: 'users#dashboard'
  get '/users/:id', to: 'users#show'
  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'
  get '/my_offers', to: 'requests#my_offers'

  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

  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end



「app\controllers\offers_controller.rb」ファイルの記述を以下のように変更します。


記述変更 app\controllers\offers_controller.rb
18行目の記述を以下の記述に変更します。

redirect_to my_offers_path, notice: "保存しました"



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: "保存しました"
                redirect_to my_offers_path, 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\views\requests」フォルダに「my_offers.html.erb」ファイルを新規作成して下さい。


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

<section class="section">
    <div class="container">
        <p class="title">申込みの確認</p>
        <table class="table is-fullwidth">
            <thead>
                <tr>
                    <th>申し込み日</th>
                    <th>リクエスト</th>
                    <th>リクエスト予算</th>
                    <th>申し込み価格</th>
                    <th>期日</th>
                    <th>ステータス</th>
                </tr>
            </thead>
            <tbody>
                <% if @offers.blank? %>
                    <tr>
                        <td colspan="6" class="has-text-centered"><h1>表示できる申込みはありません</h1></td>
                    </tr>
                <% end %>
                <% @offers.each do |o| %>
                    <tr>
                        <td><%= I18n.l(o.created_at, format: :full_date) %></td>
                        <td>
                            <%= link_to o.request.title, request_path(o.request) %>
                        </td>
                        <td><%= number_to_currency(o.request.budget) %></td>
                        <td><%= number_to_currency(o.amount) %></td>
                        <td><%= o.days %></td>
                        <td>
                            <span class="tag <%= 'is-warning' if o.pending? %> 
                                             <%= 'is-success' if o.accepted? %>
                                             <%= 'is-danger' if o.rejected? %> ">
                                <% if o.pending? %>
                                    結果待ち
                                <% elsif o.accepted? %>
                                    お仕事を頼まれました
                                <% else %>
                                    お断りされました
                                <% end %>
                            </span>
                        </td>
                    </tr>
                <% end %>
            </tbody>
        </table>
    </div>
</section>



ナビゲーションバーにリンクを追加します。


記述追加 app\views\shared\_navbar.html.erb
75行目に「<%= link_to '申込みの確認', my_offers_path, class: "navbar-item" %>」の記述を追加しています。

<nav class="navbar is-danger" role="navigation" aria-label="main navigation">
    <div class="navbar-brand">
        <a class="navbar-item" href="/">
            <h1>テストサイトOshigoto</h1>
        </a>
        <a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
            <span aria-hidden="true"></span>
            <span aria-hidden="true"></span>
            <span aria-hidden="true"></span>
        </a>
    </div>

    <div id="navbarBasicExample" class="navbar-menu">
        <div class="navbar-start">
            <div class="navbar-item">
                <div class="field has-addons">
                    <div class="control">
                        <input class="input" type="text" placeholder="どんなお仕事を?">
                    </div>
                    <div class="control">
                        <a class="button is-success">検索</a>
                    </div>
                </div>
            </div>
        </div>
        <div class="navbar-end">
            <a class="navbar-item"></a>
            <a class="navbar-item"></a>
            
            <!-- もしログインしていなかったら-->
            <% if (!user_signed_in?) %>
                <div class="navbar-item">
                    <div class="buttons">
                        <%= link_to  "新規ユーザ登録", new_user_registration_path, class: "button is-primary" %>
                        <%= link_to  "ログイン", new_user_session_path, class: "button is-light" %>
                    </div>
                </div>

            <!-- ログインしていたら -->
            <% else %>
                <div class="navbar-item has-dropdown is-hoverable">

                    <a class="navbar-item" style="margin-right: 50px;">
                        <figure class="image is-48x48 m-r-5">
                            <div style="margin-top: 0.6rem;">
                            <%= image_tag avatar_url(current_user), class: "is-rounded" %>
                            </div>
                        </figure>                                        
                        <%= current_user.full_name %>
                    </a>
                    
                    <div class="navbar-dropdown">
                        <%= link_to 'ダッシュボード', dashboard_path, class: "navbar-item" %>
                        <%= link_to  "ユーザ登録情報編集", edit_user_registration_path, class: "navbar-item" %>
                        <hr class="navbar-divider">
                        <%= link_to  "ログアウト", destroy_user_session_path, method: :delete, class: "navbar-item" %>
                    </div>
                </div>
            <% end %>
        </div>
    </div>
</nav>

<% if (user_signed_in?) && !current_page?(root_path) && !current_page?("/gigs/#{params[:id]}") && !current_page?("/users/#{params[:id]}") %>
    <nav class="navbar has-shadow" style="z-index: 5;">
        <div class="container">
            <div class="navbar">
                <%= link_to 'ダッシュボード', dashboard_path, class: "navbar-item" %>
                <div class="navbar-item has-dropdown is-hoverable">
                    <a class="navbar-link">お仕事を売る人</a>
                    <div class="navbar-dropdown">
                        <%= link_to 'お仕事を登録する', new_gig_path, class: "navbar-item" %>
                        <%= link_to '売れた注文の確認', selling_orders_path, class: "navbar-item" %>
                        <%= link_to 'リクエストを見る', all_requests_path, class: "navbar-item" %>
                        <%= link_to '申込みの確認', my_offers_path, class: "navbar-item" %>
                    </div>
                </div>
                <div class="navbar-item has-dropdown is-hoverable">
                    <a class="navbar-link">お仕事を買う人</a>
                    <div class="navbar-dropdown">
                        <%= link_to '買った注文の確認', buying_orders_path, class: "navbar-item" %>
                        <%= link_to 'お仕事をリクエストする', new_request_path, class: "navbar-item" %>
                        <%= link_to 'リクエストの確認', requests_path, class: "navbar-item" %>
                    </div>
                </div>
            </div>
        </div>
    </nav>
<% end %>

<script>
$(document).ready(function() {
  // Check for click events on the navbar burger icon
  $(".navbar-burger").click(function() {
      // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
      $(".navbar-burger").toggleClass("is-active");
      $(".navbar-menu").toggleClass("is-active");
  });
});
</script>



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


申し込みの確認
申し込みの確認


申し込みに対するアクションを実装していきます。


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


記述追加 app\controllers\offers_controller.rb(27行目)

    def accept
        if @offer.pending?
            @offer.accepted!
                flash[:notice] = "お仕事をお願いしました"
        end
        redirect_to request.referrer
    end

    def reject
        if @offer.pending?
            @offer.rejected!
            flash[:notice] = "お断りしました"
        end
        redirect_to request.referrer
    end



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: "保存しました"
                redirect_to my_offers_path, notice: "保存しました"
                
            else
                redirect_to request.referrer, flash: {error: @offer.errors.full_messages.join(', ')}
            end
        end
    end
    
    def accept
        if @offer.pending?
            @offer.accepted!
                flash[:notice] = "お仕事をお願いしました"
        end
        redirect_to request.referrer
    end
    
    def reject
        if @offer.pending?
            @offer.rejected!
            flash[:notice] = "お断りしました"
        end
        redirect_to request.referrer
    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



ルートの設定をします。


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


記述追加 config\routes.rb(24,25行目)

  put '/offers/:id/accept', to: 'offers#accept', as: 'accept_offer'
  put '/offers/:id/reject', to: 'offers#reject', as: 'reject_offer'



config\routes.rb

Rails.application.routes.draw do

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

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

  get 'pages/home'
  get '/dashboard', to: 'users#dashboard'
  get '/users/:id', to: 'users#show'
  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'
  get '/my_offers', to: 'requests#my_offers'

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

  put '/orders/:id/complete', to: 'orders#complete', as: 'complete_order'
  put '/offers/:id/accept', to: 'offers#accept', as: 'accept_offer'
  put '/offers/:id/reject', to: 'offers#reject', as: 'reject_offer'

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

  resources :requests

  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end



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


記述更新 app\views\requests\offers.html.erb(47行目)
47行目,48行目の記述を以下の記述に置き換えます。

<%= link_to accept_offer_path(o), method: :put,
            data: { confirm: "お仕事をお願いしてよろしいですか?" },
            class: "button is-small is-primary is-outlined #{'is-hidden' if !o.pending?}" do %>
    <span class="icon"><i class="far fa-check-circle fa-lg"></i></span>
    <span>お仕事をお願いする</span>
<% end %>

<%= link_to reject_offer_path(o), method: :put,
            data: { confirm: "お断りしてよろしいですか?" },
            class: "button is-small is-danger is-outlined #{'is-hidden' if !o.pending?}" do %>
    <span class="icon"><i class="far fa-times-circle fa-lg"></i></span>
    <span>お断りする</span>
<% end %>



app\views\requests\offers.html.erb

<section class="section">
    <div class="container">
        <p class="title">お申込みリスト</p>
        <table class="table is-fullwidth">
            <thead>
                <tr>
                    <th>申込み日</th>
                    <th>売り主</th>
                    <th>申し込みコメント</th>
                    <th>価格</th>
                    <th>期日</th>
                    <th>ステータス</th>
                    <th>アクション</th>
                </tr>
            </thead>
            <tbody>
                <% if @offers.blank? %>
                    <tr>
                        <td colspan="7" class="has-text-centered"><h1>表示できる申込みはありません。</h1></td>
                    </tr>
                <% end %>
                <% @offers.each do |o| %>
                    <tr>
                        <td><%= I18n.l(o.created_at, format: :full_date) %></td>
                        <td>
                            <figure class="image is-48x48">
                                <%= image_tag avatar_url(o.user), class: "is-rounded" %>
                            </figure>
                        </td>
                        <td><%= o.note %></td>
                        <td><%= number_to_currency(o.amount) %></td>
                        <td><%= o.days %></td>
                        <td>
                            <span class="tag <%= 'is-warning' if o.pending? %> 
                                            <%= 'is-success' if o.accepted? %>
                                            <%= 'is-danger' if o.rejected? %> ">
                                <% if o.pending? %>
                                    選考中
                                <% elsif o.accepted? %>
                                    お仕事をお願いしました
                                <% else %>
                                    お断りしました
                                <% end %>
                            </span>
                        </td>
                        <td>
                            <%= link_to accept_offer_path(o), method: :put,
                                        data: { confirm: "お仕事をお願いしてよろしいですか?" },
                                        class: "button is-small is-primary is-outlined #{'is-hidden' if !o.pending?}" do %>
                                <span class="icon"><i class="far fa-check-circle fa-lg"></i></span>
                                <span>お仕事をお願いする</span>
                            <% end %>

                            <%= link_to reject_offer_path(o), method: :put,
                                        data: { confirm: "お断りしてよろしいですか?" },
                                        class: "button is-small is-danger is-outlined #{'is-hidden' if !o.pending?}" do %>
                                <span class="icon"><i class="far fa-times-circle fa-lg"></i></span>
                                <span>お断りする</span>
                            <% end %>
                        </td>
                    </tr>
                <% end %>
            </tbody>
        </table>
    </div>
</section>



ブラウザ確認
http://localhost:3000/request_offers/1


アクションボタンが機能するようになりました。

アクションボタンが機能します
アクションボタンが機能します


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


[29]申し込み << [ホームに戻る] >> [31]仕事完了