Comments (8)
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.
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.
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.
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.
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 seemscounter_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.
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.
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.
@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)
- Request: Callback support on parent models HOT 1
- Multiple counters, single query HOT 5
- Incorrect count when using ID in the dynamic column name proc HOT 2
- Model.counter_culture_fix_counts does nothing after the initial run HOT 1
- Multi-level association 3-deep works in the console, but fails every test and in production HOT 3
- counter_culture_fix_counts with where clause HOT 2
- Two counters of the same model, one scoped the other not HOT 1
- jsonb support HOT 1
- what is the drawback of using active records callback instead this gem? HOT 1
- PG::UndefinedColumn: ERROR: column "nan" does not exist HOT 3
- Add "where" option to the `counter_culture` method HOT 1
- STI and Polymorphic issue with fix counts method on self-referential models HOT 4
- Updating counts is associations active HOT 1
- Dynamic column name that uses model primary key causes all updates to increment the counter HOT 2
- Column_names not accepting proc with hash HOT 1
- Call to `previous_model` is triggering `transaction_changed_attributes` callbacks causing changes to be overwritten HOT 5
- Undefined Method `current_time_from_proper_timezone' Error HOT 1
- Adding :if / :unless for conditional counter caches HOT 1
- Using namespaced classes does not work HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from counter_culture.