Skip to content

Commit 10c2c37

Browse files
committed
Initial Commit
1 parent 6d6ac83 commit 10c2c37

7 files changed

Lines changed: 194 additions & 106 deletions

File tree

Gemfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,9 @@ group :development do
5858
gem "web-console"
5959
end
6060
gem "hotwire-spark", group: :development
61+
62+
gem "prosopite", "~> 2.1"
63+
64+
gem "pg_query", "~> 6.2"
65+
66+
gem "pagy", "~> 43.3"

Gemfile.lock

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,24 @@ GEM
116116
raabro (~> 1.4)
117117
globalid (1.3.0)
118118
activesupport (>= 6.1)
119+
google-protobuf (4.34.0)
120+
bigdecimal
121+
rake (~> 13.3)
122+
google-protobuf (4.34.0-aarch64-linux-gnu)
123+
bigdecimal
124+
rake (~> 13.3)
125+
google-protobuf (4.34.0-aarch64-linux-musl)
126+
bigdecimal
127+
rake (~> 13.3)
128+
google-protobuf (4.34.0-arm64-darwin)
129+
bigdecimal
130+
rake (~> 13.3)
131+
google-protobuf (4.34.0-x86_64-linux-gnu)
132+
bigdecimal
133+
rake (~> 13.3)
134+
google-protobuf (4.34.0-x86_64-linux-musl)
135+
bigdecimal
136+
rake (~> 13.3)
119137
hotwire-spark (0.1.13)
120138
listen
121139
rails (>= 7.0.0)
@@ -206,10 +224,16 @@ GEM
206224
nokogiri (1.19.1-x86_64-linux-musl)
207225
racc (~> 1.4)
208226
ostruct (0.6.3)
227+
pagy (43.3.1)
228+
json
229+
uri
230+
yaml
209231
parallel (1.27.0)
210232
parser (3.3.10.2)
211233
ast (~> 2.4.1)
212234
racc
235+
pg_query (6.2.2)
236+
google-protobuf (>= 3.25.3)
213237
pp (0.6.3)
214238
prettyprint
215239
prettyprint (0.2.0)
@@ -218,6 +242,7 @@ GEM
218242
actionpack (>= 7.0.0)
219243
activesupport (>= 7.0.0)
220244
rack
245+
prosopite (2.1.2)
221246
psych (5.3.1)
222247
date
223248
stringio
@@ -377,6 +402,7 @@ GEM
377402
base64
378403
websocket-extensions (>= 0.1.0)
379404
websocket-extensions (0.1.5)
405+
yaml (0.4.0)
380406
zeitwerk (2.7.5)
381407

382408
PLATFORMS
@@ -399,7 +425,10 @@ DEPENDENCIES
399425
image_processing (~> 1.2)
400426
importmap-rails
401427
kamal
428+
pagy (~> 43.3)
429+
pg_query (~> 6.2)
402430
propshaft
431+
prosopite (~> 2.1)
403432
puma (>= 5.0)
404433
rails (~> 8.1.2)
405434
rubocop-rails-omakase
@@ -456,6 +485,12 @@ CHECKSUMS
456485
ffi (1.17.3-x86_64-linux-musl) sha256=086b221c3a68320b7564066f46fed23449a44f7a1935f1fe5a245bd89d9aea56
457486
fugit (1.12.1) sha256=5898f478ede9b415f0804e42b8f3fd53f814bd85eebffceebdbc34e1107aaf68
458487
globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11
488+
google-protobuf (4.34.0) sha256=bffaea30fbe2807c80667a78953b15645b3bef62b25c10ca187e4418119be531
489+
google-protobuf (4.34.0-aarch64-linux-gnu) sha256=0ab8a8a97976a2265d647e69b3ff1980c89184abdaf06d36091856c5ab37cc55
490+
google-protobuf (4.34.0-aarch64-linux-musl) sha256=0632a86df6d320eac3b335bd779499d43ad8ee6d1f8c8494b773ed5d3d5c6ab4
491+
google-protobuf (4.34.0-arm64-darwin) sha256=f83967a8095a9da676b79ba372c58fef2ca3878428bd40febfce65b3752c90d1
492+
google-protobuf (4.34.0-x86_64-linux-gnu) sha256=bbb333fbe79c16f35a2e2154cf29f3ce26f60390dba286b339861206d5435ef9
493+
google-protobuf (4.34.0-x86_64-linux-musl) sha256=0b75858a388b17e73aa4176df2e722762dbc92551b7075fdc562d33c1c6de0b0
459494
hotwire-spark (0.1.13) sha256=0a24799b0942fc9b7ea3e560a5aba3f4dd9a6086958a25929894340f920fb499
460495
i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
461496
image_processing (1.14.0) sha256=754cc169c9c262980889bec6bfd325ed1dafad34f85242b5a07b60af004742fb
@@ -493,12 +528,15 @@ CHECKSUMS
493528
nokogiri (1.19.1-x86_64-linux-gnu) sha256=1a4902842a186b4f901078e692d12257678e6133858d0566152fe29cdb98456a
494529
nokogiri (1.19.1-x86_64-linux-musl) sha256=4267f38ad4fc7e52a2e7ee28ed494e8f9d8eb4f4b3320901d55981c7b995fc23
495530
ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
531+
pagy (43.3.1) sha256=78e6c3e5125463b817cbe48eb5ed7b552af062c7db90bef4810d1f442ec61744
496532
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
497533
parser (3.3.10.2) sha256=6f60c84aa4bdcedb6d1a2434b738fe8a8136807b6adc8f7f53b97da9bc4e9357
534+
pg_query (6.2.2) sha256=316c194160ccfac8af9a7aff55cdc5b2d13bdd8bd8734976c6bddc477e779b6f
498535
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
499536
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
500537
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
501538
propshaft (1.3.1) sha256=9acc664ef67e819ffa3d95bd7ad4c3623ea799110c5f4dee67fa7e583e74c392
539+
prosopite (2.1.2) sha256=ca474e5b83bf65cdb1b3d44f848ceb3270c1e3474a9c20fd9228114bf766fd0b
502540
psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
503541
public_suffix (7.0.2) sha256=9114090c8e4e7135c1fd0e7acfea33afaab38101884320c65aaa0ffb8e26a857
504542
puma (7.2.0) sha256=bf8ef4ab514a4e6d4554cb4326b2004eba5036ae05cf765cfe51aba9706a72a8
@@ -563,6 +601,7 @@ CHECKSUMS
563601
web-console (4.3.0) sha256=e13b71301cdfc2093f155b5aa3a622db80b4672d1f2f713119cc7ec7ac6a6da4
564602
websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962
565603
websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
604+
yaml (0.4.0) sha256=240e69d1e6ce3584d6085978719a0faa6218ae426e034d8f9b02fb54d3471942
566605
zeitwerk (2.7.5) sha256=d8da92128c09ea6ec62c949011b00ed4a20242b255293dd66bf41545398f73dd
567606

568607
BUNDLED WITH
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
class ApplicationController < ActionController::Base
2+
include Pagy::Method
3+
24
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
35
allow_browser versions: :modern
46

57
# Changes to the importmap will invalidate the etag for HTML responses
68
stale_when_importmap_changes
9+
10+
unless Rails.env.production?
11+
around_action :n_plus_one_detection
12+
13+
def n_plus_one_detection
14+
Prosopite.scan
15+
yield
16+
ensure
17+
Prosopite.finish
18+
end
19+
end
720
end
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
class DashboardController < ApplicationController
22
def index
3-
@products = Product.all
4-
@orders = Order.all
5-
@reviews = Review.all
6-
@vendors = Vendor.all
3+
@pagy_products, @products = pagy(:offset, Product.includes(:vendor, :category, :reviews))
4+
@pagy_orders, @orders = pagy(:offset, Order.includes(:customer, order_items: :product))
5+
@pagy_reviews, @reviews = pagy(:offset, Review.includes(:customer, :product))
6+
@pagy_vendors, @vendors = pagy(:offset, Vendor.includes(products: :order_items))
77
end
88
end

app/views/dashboard/index.html.erb

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,43 @@
44

55
<div class="mb-10">
66
<h2 class="font-semibold text-xl mb-3">Products (<%= @products.count %>)</h2>
7-
<div class="overflow-x-auto">
8-
<table class="min-w-full border border-gray-300">
9-
<thead class="bg-gray-100">
10-
<tr>
11-
<th class="px-4 py-2 text-left text-sm font-medium text-gray-700 border-b">Name</th>
12-
<th class="px-4 py-2 text-left text-sm font-medium text-gray-700 border-b">SKU</th>
13-
<th class="px-4 py-2 text-right text-sm font-medium text-gray-700 border-b">Price</th>
14-
<th class="px-4 py-2 text-left text-sm font-medium text-gray-700 border-b">Vendor</th>
15-
<th class="px-4 py-2 text-left text-sm font-medium text-gray-700 border-b">Category</th>
16-
<th class="px-4 py-2 text-right text-sm font-medium text-gray-700 border-b">Avg Rating</th>
17-
<th class="px-4 py-2 text-right text-sm font-medium text-gray-700 border-b">Reviews</th>
18-
</tr>
19-
</thead>
20-
<tbody>
21-
<% @products.each do |product| %>
22-
<tr class="hover:bg-gray-50">
23-
<td class="px-4 py-2 text-sm border-b"><%= product.name %></td>
24-
<td class="px-4 py-2 text-sm text-gray-500 border-b"><%= product.sku %></td>
25-
<td class="px-4 py-2 text-sm text-right border-b"><%= number_to_currency(product.price) %></td>
26-
<td class="px-4 py-2 text-sm border-b"><%= product.vendor.name %></td>
27-
<td class="px-4 py-2 text-sm border-b"><%= product.category.name %></td>
28-
<td class="px-4 py-2 text-sm text-right border-b">
29-
<% if product.reviews.any? %>
30-
<%= (product.reviews.sum(:rating).to_f / product.reviews.size).round(1) %>
31-
<% else %>
32-
N/A
33-
<% end %>
34-
</td>
35-
<td class="px-4 py-2 text-sm text-right border-b"><%= product.reviews.count %></td>
36-
</tr>
37-
<% end %>
38-
</tbody>
39-
</table>
40-
</div>
7+
<div class="overflow-x-auto">
8+
<%= turbo_frame_tag :products do %>
9+
<table class="min-w-full border border-gray-300">
10+
<thead class="bg-gray-100">
11+
<tr>
12+
<th class="px-4 py-2 text-left text-sm font-medium text-gray-700 border-b">Name</th>
13+
<th class="px-4 py-2 text-left text-sm font-medium text-gray-700 border-b">SKU</th>
14+
<th class="px-4 py-2 text-right text-sm font-medium text-gray-700 border-b">Price</th>
15+
<th class="px-4 py-2 text-left text-sm font-medium text-gray-700 border-b">Vendor</th>
16+
<th class="px-4 py-2 text-left text-sm font-medium text-gray-700 border-b">Category</th>
17+
<th class="px-4 py-2 text-right text-sm font-medium text-gray-700 border-b">Avg Rating</th>
18+
<th class="px-4 py-2 text-right text-sm font-medium text-gray-700 border-b">Reviews</th>
19+
</tr>
20+
</thead>
21+
<tbody>
22+
<% @products.each do |product| %>
23+
<tr class="hover:bg-gray-50">
24+
<td class="px-4 py-2 text-sm border-b"><%= product.name %></td>
25+
<td class="px-4 py-2 text-sm text-gray-500 border-b"><%= product.sku %></td>
26+
<td class="px-4 py-2 text-sm text-right border-b"><%= number_to_currency(product.price) %></td>
27+
<td class="px-4 py-2 text-sm border-b"><%= product.vendor.name %></td>
28+
<td class="px-4 py-2 text-sm border-b"><%= product.category.name %></td>
29+
<td class="px-4 py-2 text-sm text-right border-b">
30+
<% if product.reviews.any? %>
31+
<%= (product.reviews.sum(&:rating).to_f / product.reviews.size).round(1) %>
32+
<% else %>
33+
N/A
34+
<% end %>
35+
</td>
36+
<td class="px-4 py-2 text-sm text-right border-b"><%= product.reviews.size %></td>
37+
</tr>
38+
<% end %>
39+
</tbody>
40+
</table>
41+
<%== @pagy_products.series_nav %>
42+
<% end %>
43+
</div>
4144
</div>
4245

4346
<div class="mb-10">
@@ -121,7 +124,7 @@
121124
<tr class="hover:bg-gray-50">
122125
<td class="px-4 py-2 text-sm border-b"><%= vendor.name %></td>
123126
<td class="px-4 py-2 text-sm text-gray-500 border-b"><%= vendor.contact_email %></td>
124-
<td class="px-4 py-2 text-sm text-right border-b"><%= vendor.products.count %></td>
127+
<td class="px-4 py-2 text-sm text-right border-b"><%= vendor.products.size %></td>
125128
<td class="px-4 py-2 text-sm text-right border-b">
126129
<%= number_to_currency(
127130
vendor.products.sum { |p| p.order_items.sum { |oi| oi.quantity * oi.unit_price } }

config/environments/development.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
Rails.application.configure do
44
# Settings specified here will take precedence over those in config/application.rb.
5+
config.after_initialize do
6+
Prosopite.rails_logger = true
7+
end
58

69
# Make code changes take effect immediately without server restart.
710
config.enable_reloading = true

0 commit comments

Comments
 (0)