Giter VIP home page Giter VIP logo

Comments (8)

magnusvk avatar magnusvk commented on June 16, 2024

Nothing looks wrong at first glance. Are you inserting CategoriesProduct without callbacks in some way perhaps? In that case counter_culture wouldn't work.

from counter_culture.

jwilson114 avatar jwilson114 commented on June 16, 2024

Ive got an almost identical set up configuration and counter_culture using column_names and a specific scope. But the count is not changing when the product_category relation is created or destroyed. I can confirm callbacks are triggering in the joining model

class Product < ApplicationRecord
  has_many :product_category_products, dependent: :destroy
  has_many :product_categories, through: :product_category_products

  scope :active, -> do
    where("active_sales_channel = TRUE")
  end
end

class ProductCategory < ApplicationRecord
  has_many :product_category_products, dependent: :destroy
  has_many :products, through: :product_category_products
end

class ProductCategoryProduct < ApplicationRecord
  belongs_to :product_category
  belongs_to :product

  counter_culture :product_category, column_name: 'active_products_count', execute_after_commit: true, column_names: -> { {
    Product.active => :active_products_count,
  } }

  # also tried
  # {
  #   ['products.active_sales_channel = TRUE'] => :active_products_count
  # }
end

would also appreciate any assistance. My expectation is that when the product.active_sales_channel is true and ProductCategoryProduct record is created the ProductCategory.active_products_count increments. If product.active_sales_channel is false then ProductCategory.active_products_count does not increment.

from counter_culture.

exocode avatar exocode commented on June 16, 2024

Nothing looks wrong at first glance. Are you inserting CategoriesProduct without callbacks in some way perhaps? In that case counter_culture wouldn't work.

Nothing special:
Product.update(categories: Category.all.sample(2)
The new relations in CategoriesProduct are created, the old ones deleted. The new entries are properly counted, but the counter does not update the old entries.

When I do a Product.unscoped.destroy_all the products_count in the Category model wont get updated. ONLY a
CategoriesProduct.counter_culture_fix_counts will solve the problem and results in this
{:entity=>"Category", :id=>5811, :what=>"products_count", :wrong=>1, :right=>0}

from counter_culture.

magnusvk avatar magnusvk commented on June 16, 2024

Does Product.update call callbacks? I haven't ever used that class-level method before. Have you tried Product.find_each { |product product.update!(categories: Category.all.sample(2)) }

from counter_culture.

exocode avatar exocode commented on June 16, 2024

Does Product.update call callbacks?

sorry for not beeing clear enough, it's NOT a class level method, you can take any product instance:

Product.last.update(categories:[ Category.find(2547)])

And yes they are fired in that order:

categories
| id 2547 | product_count: 0 |

Product.unscoped.last.categories << Category.find(2547)

  Product Load (2.3ms)  SELECT "products".* FROM "products" ORDER BY "products"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Category Load (2.2ms)  SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2  [["id", 2547], ["LIMIT", 1]]
before_save CategoriesProduct id:  category_id: 2547 product: 429
before_create CategoriesProduct id:  category_id: 2547 product: 429
  TRANSACTION (1.5ms)  BEGIN
  CategoriesProduct Create (1.4ms)  INSERT INTO "categories_products" ("category_id", "product_id") VALUES ($1, $2) RETURNING "id"  [["category_id", 2547], ["product_id", 429]]
  Category Update All (1.3ms)  UPDATE "categories" SET "products_count" = COALESCE("products_count", 0) + 1 WHERE "categories"."id" = $1  [["id", 2547]]
after_create CategoriesProduct id: 118 category_id: 2547 product: 429
after_save CategoriesProduct id: 118 category_id: 2547 product: 429
  TRANSACTION (1.6ms)  COMMIT
after_commit CategoriesProduct id: 118 category_id: 2547 product: 429
  Category Load (2.3ms)  SELECT "categories".* FROM "categories" INNER JOIN "categories_products" ON "categories"."id" = "categories_products"."category_id" WHERE "categories_products"."product_id" = $1 /* loading for inspect */ LIMIT $2  [["product_id", 429], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Category id: 2547, name: "Tischsets", created_at: "2022-09-01 10:38:07.796610000 +0000", updated_at: "2022-09-01 19:42:40.669052000 +0000", ancestry: "536/4171/601", ancestry_depth: 3, gid: nil, slug: "tischsets", children_count: 0, products_count: 1, path_de_de: "Heim & Garten > Bett- und Haushaltswäsche > Tischw...", path_en_uk: "Home & Garden > Linens & Bedding > Table Linen > P...", path_en_us: "Home & Garden > Linens & Bedding > Table Linens > ...", category_parent_id: 601, subtree_count: nil, categories_count: 0>]>

categories
| id 2547 | product_count: 1 |

categories_products
| category_id: 2547 | product_id: 429 |

> Product.unscoped.last.update(categories:[ Category.find(2548)])

  Product Load (1.8ms)  SELECT "products".* FROM "products" ORDER BY "products"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Category Load (1.3ms)  SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2  [["id", 2548], ["LIMIT", 1]]
  TRANSACTION (1.2ms)  BEGIN
  Category Load (2.0ms)  SELECT "categories".* FROM "categories" INNER JOIN "categories_products" ON "categories"."id" = "categories_products"."category_id" WHERE "categories_products"."product_id" = $1  [["product_id", 429]]
  CategoriesProduct Destroy (1.1ms)  DELETE FROM "categories_products" WHERE "categories_products"."product_id" = $1 AND "categories_products"."category_id" = $2  [["product_id", 429], ["category_id", 2547]]
before_save CategoriesProduct id:  category_id: 2548 product: 429
before_create CategoriesProduct id:  category_id: 2548 product: 429
  CategoriesProduct Create (1.1ms)  INSERT INTO "categories_products" ("category_id", "product_id") VALUES ($1, $2) RETURNING "id"  [["category_id", 2548], ["product_id", 429]]
  Category Update All (1.1ms)  UPDATE "categories" SET "products_count" = COALESCE("products_count", 0) + 1 WHERE "categories"."id" = $1  [["id", 2548]]
after_create CategoriesProduct id: 119 category_id: 2548 product: 429
after_save CategoriesProduct id: 119 category_id: 2548 product: 429
  Shop Load (1.0ms)  SELECT "shops".* FROM "shops" WHERE "shops"."id" = $1 LIMIT $2  [["id", 264], ["LIMIT", 1]]
  Product Exists? (1.1ms)  SELECT 1 AS one FROM "products" WHERE "products"."ean" = $1 AND "products"."id" != $2 AND "products"."shop_id" = $3 LIMIT $4  [["ean", 2746275375310], ["id", 429], ["shop_id", 264], ["LIMIT", 1]]
  Product Exists? (1.0ms)  SELECT 1 AS one FROM "products" WHERE "products"."sku" = $1 AND "products"."id" != $2 AND "products"."shop_id" = $3 LIMIT $4  [["sku", "GoodDiscount817882"], ["id", 429], ["shop_id", 264], ["LIMIT", 1]]
  Product Exists? (1.1ms)  SELECT 1 AS one FROM "products" WHERE "products"."gtin" = $1 AND "products"."id" != $2 AND "products"."shop_id" = $3 LIMIT $4  [["gtin", "5454010867118"], ["id", 429], ["shop_id", 264], ["LIMIT", 1]]
before_save Product id: 429
  Product Exists? (1.1ms)  SELECT 1 AS one FROM "products" WHERE "products"."ean" = $1 AND "products"."id" != $2 AND "products"."shop_id" = $3 LIMIT $4  [["ean", 2746275375310], ["id", 429], ["shop_id", 264], ["LIMIT", 1]]
  Product Exists? (1.3ms)  SELECT 1 AS one FROM "products" WHERE "products"."sku" = $1 AND "products"."id" != $2 AND "products"."shop_id" = $3 LIMIT $4  [["sku", "GoodDiscount817882"], ["id", 429], ["shop_id", 264], ["LIMIT", 1]]
  Product Exists? (1.2ms)  SELECT 1 AS one FROM "products" WHERE "products"."gtin" = $1 AND "products"."id" != $2 AND "products"."shop_id" = $3 LIMIT $4  [["gtin", "5454010867118"], ["id", 429], ["shop_id", 264], ["LIMIT", 1]]
before_update Product id: 429
after_update Product id: 429
after_save Product id: 429
  TRANSACTION (1.5ms)  COMMIT
after_commit Product id: 429
after_commit CategoriesProduct id: 119 category_id: 2548 product: 429
=> true

categories
| 2547 | product_count: 1 | ---> is still "1" should be "0"
| 2548 | product_count: 1 | ----> is one, so it's correct

categories_products
| category_id: 2548 | product_id: 429 |
|                   |                 | ---> there is no 2547 anymore, as expected

Let's try to fix it:

>> CategoriesProduct.counter_culture_fix_counts

=> [{:entity=>"Category", :id=>2547, :what=>"products_count", :wrong=>1, :right=>0},
    {:entity=>"Category", :id=>2548, :what=>"products_count", :wrong=>1, :right=>0}]

Now the counter should be fixed, but fixes it wrong:
There is still a relation (2548 should be 1) but is counted as "0" (zero):

categories
| 2547 | product_count: 0 | 
| 2548 | product_count: 0 | ---> is "0" after "fixing" should be now "1"

Creating a CategoriesProduct relation counts up properly in the categories table, only when I "overwrite" via some_product.update(categories: [Category.find(1)]) it does not decrease the counter.

ONLY when I use "destroy" the counter counts down as expected:

> Product.unscoped.last.categories.destroy(Product.unscoped.last.categories.last)

  Product Load (3.5ms)  SELECT "products".* FROM "products" ORDER BY "products"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Product Load (1.4ms)  SELECT "products".* FROM "products" ORDER BY "products"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Category Load (1.8ms)  SELECT "categories".* FROM "categories" INNER JOIN "categories_products" ON "categories"."id" = "categories_products"."category_id" WHERE "categories_products"."product_id" = $1 ORDER BY "categories"."id" DESC LIMIT $2  [["product_id", 429], ["LIMIT", 1]]
  TRANSACTION (0.9ms)  BEGIN
  CategoriesProduct Load (1.2ms)  SELECT "categories_products".* FROM "categories_products" WHERE "categories_products"."product_id" = $1 AND "categories_products"."category_id" = $2  [["product_id", 429], ["category_id", 2547]]
  Category Load (1.3ms)  SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2  [["id", 2547], ["LIMIT", 1]]
  Category Update All (1.2ms)  UPDATE "categories" SET "products_count" = COALESCE("products_count", 0) - 1 WHERE "categories"."id" = $1  [["id", 2547]]
before_destroy CategoriesProduct id: 116 category_id: 2547 product: 429
  CategoriesProduct Destroy (1.0ms)  DELETE FROM "categories_products" WHERE "categories_products"."id" = $1  [["id", 116]]
after_destroy CategoriesProduct id: 116 category_id: 2547 product: 429
  TRANSACTION (1.4ms)  COMMIT
after_commit CategoriesProduct id: 116 category_id: 2547 product: 429

The readme says:

Updates counter cache when values change, not just when creating and destroying
It seems counter_culture does not recognize this kind of updates.

How sovle this usecase when also "counter_culture_fix_counts" does not fix properly

from counter_culture.

exocode avatar exocode commented on June 16, 2024

I've created a rspec test for this in one file, to observe this case:
just run ruby test.rb to see the results.

https://gist.github.com/exocode/6d635f226f008e4c0e35c45e5b332de9

Maybe I'm doing it wrong, I don't know

Thank you in advance

from counter_culture.

magnusvk avatar magnusvk commented on June 16, 2024

Can you open a PR with a failing spec within the existing counter culture specs? I'm not in a place where I can provide support for this gem, but if you can come up with a failing spec I'm certainly happy to look at it.

from counter_culture.

exocode avatar exocode commented on June 16, 2024

@magnusvk I've added the PR with example specs (the very last one, is the failing one, others are only sanity checks)

from counter_culture.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.