LIFE PROGRAMMING

Adminアカウントで売上を見れるようにする【いせ日記】









今日はAdminアカウントの/adminsのページでその月の売上と過去全部の売上を見れるようにしていきます。

今日の作業
・Adminアカウントで過去の売上と今月の売上を見れるようにする
・Adminアカウントで売上の詳細を見れるようにする

作業手順

Adminアカウントで売れた商品を取得する

Adminが作成したproductsの中で、売れた商品(purchase_record_products)を検索しなければいけません。そのため、下記のようにjoinsというメソッドを使って、ProductPuchaseRecordProductを結びつけます。

$rails c
2.5.3 :001 >Admin.last.products.joins(:purchase_record_products)
 => #<ActiveRecord::AssociationRelation [#<Product id: 1, admin_id: 1, user_id: nil, name: "test1", description: "これはテスト1用の商品です。", price: 1000, created_at: "2020-10-10 10:14:37", updated_at: "2020-10-10 10:14:37", image: "alvin-mahmudov-vKuEhorbvYI-unsplash__1_.jpg">, #<Product id: 1, admin_id: 1, user_id: nil, name: "test1", description: "これはテスト1用の商品です。", price: 1000, created_at: "2020-10-10 10:14:37", updated_at: "2020-10-10 10:14:37", image: "alvin-mahmudov-vKuEhorbvYI-unsplash__1_.jpg">,

無事に2つのモデルを結ぶことができました。

それではadminモデル下記のようなメソッドを追加します。

class Admin < ApplicationRecord
  devise :database_authenticatable,
         :recoverable, :rememberable, :validatable
  has_many :products, dependent: :destroy
  
  def sales
  end
  
  def sales_one_month
  end 
  
end

salesメソッドにまずは先ほどやったjoinsメソッドを使って購入された商品の一覧を取得します。そして、それを計算して合計値を出します。

  def sales
    sold_products = self.products.joins(:purchase_record_products)
    sold_products.sum(:price)
  end

こんな感じになりますね。めちゃシンプルです。

次にsales_one_monthの方ですね。1ヶ月の売上を見れるようにしなければいけません。

そのためには、購入した今月の売上を検索しなければいけません。検索するには下記のようなコードを追加します。

where(created_at: Time.now.all_month)

これで今月に作成したものを検索することができるそうです。

さらにjoinspurchase_record_productsとテーブルを連結させたので、下記のように結合先のテーブル名を指定して検索をします。

モデル名.joins(:関連名).where(結合先のテーブル名: { カラム名: 値 })

これらを合わせると以下のようになりますね。

  def sales_one_month
    sold_products = products.joins(:purchase_record_products).where({ purchase_record_products: {created_at: Time.now.all_month} })
    sold_products.sum(:price)
  end 

きちんと動作するかどうか確認してみます。

$ rails c 
2.5.3 :001 > Admin.last.sales
  Admin Load (0.3ms)  SELECT  `admins`.* FROM `admins` ORDER BY `admins`.`id` DESC LIMIT 1
   (0.2ms)  SELECT SUM(`products`.`price`) FROM `products` INNER JOIN `purchase_record_products` ON `purchase_record_products`.`product_id` = `products`.`id` WHERE `products`.`admin_id` = 1
 => 14000
2.5.3 :002 > Admin.last.sales_one_month
  Admin Load (0.7ms)  SELECT  `admins`.* FROM `admins` ORDER BY `admins`.`id` DESC LIMIT 1
   (0.3ms)  SELECT SUM(`products`.`price`) FROM `products` INNER JOIN `purchase_record_products` ON `purchase_record_products`.`product_id` = `products`.`id` WHERE `products`.`admin_id` = 1 AND `purchase_record_products`.`created_at` BETWEEN '2020-10-01 00:00:00' AND '2020-10-31 23:59:59'
 => 14000 

無事両方とも動作しました。よかったです。

そしたらこの二つをトップページに表示させます。

売上を表示させる

<div class="container">
  <h2 class="text-center">Adminトップページ</h2>
   <ul class="list-group list-unstyled">
        <li class="admin-sales-all d-flex justify-content-between border">
          <p>今までの売上  <span><%=current_admin.sales.to_s %>円</span></p>
          <a class="p-0 m-0"><%=link_to '詳細', admins_sales_record_path, class: "btn btn-success"%></a>
        </li>
        <li class="admin-sales-one-month d-flex justify-content-between border">
          <p>今月の売上   <span><%=current_admin.sales_one_month.to_s %>円</span></p>
          <a><%=link_to '詳細', admins_sales_record_path, class: "btn btn-success"%></a>
      </li>
    </ul>
   </h2>
</div>

ほとんどカートの中身と表示設定は変わりません。

それでは、売上の詳細を見れるようにします。

売上の詳細を見れるようにする

 resource :sales_record, only: [:show]
class Admins::SalesRecordsController < Admins::ApplicationController
    def show
    end
end

Adminからpurchase_record_productsを閲覧できるようにAdminhas_manyを追加します。

has_many :purchase_record_products, through: :products
<table class="table">
    <thead>
        <tr>
            <th>商品名</th>
            <th>価格</th>
            <th>購入日</th>
        </tr>
    </thead>
    <tbody>
      <% @purchase_record_products.each do |prd| %>
        <% product = prd.product %>
        <tr>
            <td><%=product.name %></td>
            <td><%=product.price %>円</td>
            <td><%=product.created_at %></td>
        </tr>
      <% end %>
    </tbody>
</table>

N+1問題

ここでN+1問題が発生するとのことです。

N+1問題とはなんだ。。

ループ処理の中で都度SQLを発行してしまい、大量のSQLが発行されてパフォーマンスが低下してしまう問題のことです。

日常生活で例えるなら、スーパーで商品を1点ずつお会計するようなもの。
それだけ無駄なことを行なっている状態を指します。

え、そんなアホなこと普通はしないって思いますよね?
でもRailsを使用していると往往にしてこの問題が発生してしまうのです。
引用:https://qiita.com/massaaaaan/items/4eb770f20e636f7a1361

なるほど、めちゃ効率悪いですね。

ということでpreloadメソッドを使って、解決していきます。

@purchase_record_products = current_admin.purchase_record_products.preload(:product)

これだけで問題解決しました。

まとめ【いせ日記】

本当は今月の売上の詳細の表示まで終わらせたかったのですが、本日はここまでにします😭

本日のプログラミング時間: 9時間

今日は休日だったので、9時間学習しました!9時間で終わらせられなかったのが残念です。。

途中エラーに苦しめられて3時間くらいエラーと戦っていました笑

あとは4時間くらいはググったりして、どんな感じにすればよくなるのかを考えてました。

あとの2時間はブログ書きながらコードを書くって感じですね!

本当はエラーの内容とかをもう少し詳細に書きたかったのですが、エラーに対処するのが大変でそこまで出来ませんでした。。

今後はもう少し過程の部分をかけたらなと思います。

あともう少しで終わらせられたんですが、明日に持ち越します😅

それではまた明日もよろしくお願い致します。

最後まで読んでくださりありがとうございました🙇‍♂️

-LIFE, PROGRAMMING

Copyright © Iseblog ,@2020 All Rights Reserved.