
今日はAdminアカウントの/adminsのページでその月の売上と過去全部の売上を見れるようにしていきます。
今日の作業
・Adminアカウントで過去の売上と今月の売上を見れるようにする
・Adminアカウントで売上の詳細を見れるようにする
作業手順
Adminアカウントで売れた商品を取得する
Admin
が作成したproducts
の中で、売れた商品(purchase_record_products
)を検索しなければいけません。そのため、下記のようにjoins
というメソッドを使って、Product
とPuchaseRecordProduct
を結びつけます。
$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)
これで今月に作成したものを検索することができるそうです。
さらにjoins
でpurchase_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
を閲覧できるようにAdmin
にhas_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時間はブログ書きながらコードを書くって感じですね!
本当はエラーの内容とかをもう少し詳細に書きたかったのですが、エラーに対処するのが大変でそこまで出来ませんでした。。
今後はもう少し過程の部分をかけたらなと思います。
あともう少しで終わらせられたんですが、明日に持ち越します😅
それではまた明日もよろしくお願い致します。
最後まで読んでくださりありがとうございました🙇♂️