From d6c1a96506a91b63fbf11ff43eec8712ad7a619a Mon Sep 17 00:00:00 2001
From: "sentry-autofix[bot]"
<157164994+sentry-autofix[bot]@users.noreply.github.com>
Date: Tue, 7 Jan 2025 14:57:38 -0800
Subject: [PATCH] Add Active Model Serializers and Update Product Serialization
(#655)
Co-authored-by: sentry-autofix[bot] <157164994+sentry-autofix[bot]@users.noreply.github.com>
---
react/src/components/Products.jsx | 8 ++++--
ruby-on-rails/Gemfile | 2 ++
.../controllers/api/v1/products_controller.rb | 28 +++++--------------
.../app/serializers/product_serializer.rb | 18 ++++++++++++
4 files changed, 32 insertions(+), 24 deletions(-)
create mode 100644 ruby-on-rails/app/serializers/product_serializer.rb
diff --git a/react/src/components/Products.jsx b/react/src/components/Products.jsx
index 4802e510..565dae03 100644
--- a/react/src/components/Products.jsx
+++ b/react/src/components/Products.jsx
@@ -134,11 +134,13 @@ function Products({ frontendSlowdown, backend, productsExtremelySlow, productsBe
{products.map((product, i) => {
+ // Ensure reviews is an array and handle edge cases
+ const reviews = Array.isArray(product.reviews) ? product.reviews : [];
const averageRating = (
- product.reviews.reduce((a, b) => a + (b['rating'] || 0), 0) /
- product.reviews.length
+ reviews.length > 0
+ ? reviews.reduce((a, b) => a + (b['rating'] || 0), 0) / reviews.length
+ : 0
).toFixed(1);
-
let stars = [1, 2, 3, 4, 5].map((index) => {
if (index <= averageRating) {
return (
diff --git a/ruby-on-rails/Gemfile b/ruby-on-rails/Gemfile
index 62140c82..44f79bb6 100644
--- a/ruby-on-rails/Gemfile
+++ b/ruby-on-rails/Gemfile
@@ -18,6 +18,8 @@ gem 'nokogiri', '~>1.17.2'
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
gem 'rack-cors'
gem 'pg'
+# Add serializer for proper JSON handling
+gem 'active_model_serializers', '~> 0.10.13'
gem "stackprof"
gem "sentry-ruby"
diff --git a/ruby-on-rails/app/controllers/api/v1/products_controller.rb b/ruby-on-rails/app/controllers/api/v1/products_controller.rb
index f85eb990..ace44196 100644
--- a/ruby-on-rails/app/controllers/api/v1/products_controller.rb
+++ b/ruby-on-rails/app/controllers/api/v1/products_controller.rb
@@ -3,32 +3,18 @@ def index
# get Sentry tags in application_controller.rb
set_Sentry_tags
+
transaction = Sentry.get_current_scope.get_transaction || Sentry.start_transaction(name: "custom transaction")
span_products_db = transaction.start_child(op: "custom.products_db_call")
- sleep 0.25
- products = Products.select("id, title, description, descriptionfull, price, img, imgcropped, Null as pg_sleep, Null as reviews")
- sleep 0.25
+ # Eager load reviews to prevent n+1 queries and ensure proper serialization
+ products = Products.includes(:reviews)
+ .select("id, title, description, descriptionfull, price, img, imgcropped")
span_products_db.finish
- # n+1 to db if done this way
- products.each do |prod_slow|
- span_products_slow_db = transaction.start_child(op: "custom.reviews_slow_db_call")
- prod_slow["pg_sleep"] = ""
- prod_slow["reviews"] = []
- prod_slow["reviews"] = Reviews.select("id, productid, rating, customerid, description, created, Null as pg_sleep").where("productid="+prod_slow.id.to_s)
- span_products_slow_db.finish
- end
-
- # fewer db calls this way -- done in products-join
- # span_reviews_db = transaction.start_child(op: "custom.reviews_db_call")
- # sleep 0.25
- # reviews = Reviews.select("id, productid, rating, customerid, description, created, Null as pg_sleep")
- # sleep 0.25
- # span_reviews_db.finish
-
- # span_response = transaction.start_child(op: "custom.construct_response_object")
- # products.each do |prod|
+ # Use the serializer to properly format the response
+ render json: products, each_serializer: ProductSerializer, status: 200
+ end
# prod["pg_sleep"] = ""
# reviews_arr = []
# reviews.each do |review|
diff --git a/ruby-on-rails/app/serializers/product_serializer.rb b/ruby-on-rails/app/serializers/product_serializer.rb
new file mode 100644
index 00000000..c068a289
--- /dev/null
+++ b/ruby-on-rails/app/serializers/product_serializer.rb
@@ -0,0 +1,18 @@
+class ProductSerializer < ActiveModel::Serializer
+ attributes :id, :title, :description, :descriptionfull, :price, :img, :imgcropped, :pg_sleep, :reviews
+
+ def reviews
+ reviews_relation = object.reviews.select("id, productid, rating, customerid, description, created")
+ reviews_relation.map do |review|
+ {
+ id: review.id,
+ productid: review.productid,
+ rating: review.rating,
+ customerid: review.customerid,
+ description: review.description,
+ created: review.created,
+ pg_sleep: nil
+ }
+ end
+ end
+end
\ No newline at end of file