Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

counter_cache doesn't update when :order specified on has_many association

#3344

When using << to add child items to a parent collection, those items will not be counted in the parent's counter_cache if they already exist.

This only seems to happen if :order is specified on the has_many association. I assume it happens with other options, but I've only tested with :order.

Note that these items already exist within the database. Adding items via << for new entries seems to work fine.

BEFORE - NOT WORKING


class Expense < ActiveRecord::Base
  belongs_to :invoice_line_item, :counter_cache => true
  # more code...
end

class InvoiceLineItem < ActiveRecord::Base
  has_many :expenses, :order => "created_on ASC"
  # more code...
end

>> ili.expenses
=> []
>> ili.expenses << exp
=> [#<Expense id: 1, account_id: 3, person_id: 0, assigned_id: "000001", project_id: nil, invoice_line_item_id: 129484, category: "food", amount_in_cents: 20000, amount_currency: "USD", description: nil, created_on: "2009-10-07 18:06:00", is_billable: false>]
>> ili.expenses.count
=> 1
>> ili.expenses.size
=> 1
>> ili.reload
=> #<InvoiceLineItem id: 129484, account_id: 3, invoice_id: 58541, title: "line item", quantity: 0.0, price_per_in_cents: 0, price_per_currency: "", flat_fee_in_cents: 0, flat_fee_currency: "", final_cost_in_cents: 0, final_cost_currency: "USD", basecamp_id: nil, rank: nil, invoice_schedule_id: 0, line_item_id: nil, description: nil, is_taxable: true, person_id: nil, time_entries_count: 0, expenses_count: 0>
>> ili.expenses.size
=> 0
>> ili.expenses_count
=> 0
>> ili.expenses.count
=> 1
>>

AFTER - WORKING


class Expense < ActiveRecord::Base
  belongs_to :invoice_line_item, :counter_cache => true
  # more code...
end

class InvoiceLineItem < ActiveRecord::Base
  has_many :expenses # REMOVED THE ORDER CLAUSE
  # more code...
end

>> ili.expenses
=> []
>> ili.expenses << exp
=> [#<Expense id: 2, account_id: 3, person_id: 0, assigned_id: "000002", project_id: nil, invoice_line_item_id: 129485, category: "tools", amount_in_cents: 1000, amount_currency: "USD", description: nil, created_on: "2009-10-07 18:09:02", is_billable: false>]
>> ili.expenses.size
=> 1
>> ili.reload.expenses_count
=> 1
>> ili.expenses.size
=> 1
>>

Reported by subimage · October 7th, 2009 @ 08:37 PM

State: stale
Milestone: none
Assigned to: nobody
Importance: none

Activity

  1. Mark Turner
    Mark Turner

    Cant Duplicate In Rails 2.3.4

    app/models/invoice_line_item.rb

    class InvoiceLineItem < ActiveRecord::Base
      has_many :expenses, :order => "created_at ASC"
    end
    

    app/models/expense.rb

    class Expense < ActiveRecord::Base
      belongs_to :invoice_line_item, :counter_cache => true
    end
    

    Console Session:

    Loading development environment (Rails 2.3.4)
    >> ili = InvoiceLineItem.new
    +----------------+------------+------------+
    | expenses_count | created_at | updated_at |
    +----------------+------------+------------+
    |                |            |            |
    +----------------+------------+------------+
    1 row in set
    >> ili.save
      InvoiceLineItem Create (0.8ms)   INSERT INTO "invoice_line_items" ("created_at", "expenses_count", "updated_at") VALUES('2009-10-08 07:26:05', NULL, '2009-10-08 07:26:05')
    => true
    >> ili
    +----+----------------+-------------------------+-------------------------+
    | id | expenses_count | created_at              | updated_at              |
    +----+----------------+-------------------------+-------------------------+
    | 7  |                | 2009-10-08 07:26:05 UTC | 2009-10-08 07:26:05 UTC |
    +----+----------------+-------------------------+-------------------------+
    1 row in set
    >> ili.expenses << Expense.new
      Expense Create (0.3ms)   INSERT INTO "expenses" ("created_at", "updated_at", "invoice_line_item_id") VALUES('2009-10-08 07:26:46', '2009-10-08 07:26:46', 7)
      InvoiceLineItem Load (0.2ms)   SELECT * FROM "invoice_line_items" WHERE ("invoice_line_items"."id" = 7) 
      InvoiceLineItem Update (0.1ms)   UPDATE "invoice_line_items" SET "expenses_count" = COALESCE("expenses_count", 0) + 1 WHERE ("id" = 7) 
      Expense Load (0.4ms)   SELECT * FROM "expenses" WHERE ("expenses".invoice_line_item_id = 7) ORDER BY created_at ASC
    +----+----------------------+-------------------------+-------------------------+
    | id | invoice_line_item_id | created_at              | updated_at              |
    +----+----------------------+-------------------------+-------------------------+
    | 5  | 7                    | 2009-10-08 07:26:46 UTC | 2009-10-08 07:26:46 UTC |
    +----+----------------------+-------------------------+-------------------------+
    1 row in set
    >> ili.expenses
    +----+----------------------+-------------------------+-------------------------+
    | id | invoice_line_item_id | created_at              | updated_at              |
    +----+----------------------+-------------------------+-------------------------+
    | 5  | 7                    | 2009-10-08 07:26:46 UTC | 2009-10-08 07:26:46 UTC |
    +----+----------------------+-------------------------+-------------------------+
    1 row in set
    >> ili.expenses.size
    => 1
    >> ili.expenses.count
      SQL (0.3ms)   SELECT count(*) AS count_all FROM "expenses" WHERE ("expenses".invoice_line_item_id = 7) 
    => 1
    >> ili.expenses_count
    => nil
    >> ili.save
    => true
    >> ili.reload
      InvoiceLineItem Load (0.3ms)   SELECT * FROM "invoice_line_items" WHERE ("invoice_line_items"."id" = 7) 
    +----+----------------+-------------------------+-------------------------+
    | id | expenses_count | created_at              | updated_at              |
    +----+----------------+-------------------------+-------------------------+
    | 7  | 1              | 2009-10-08 07:26:05 UTC | 2009-10-08 07:26:05 UTC |
    +----+----------------+-------------------------+-------------------------+
    1 row in set
    >> ili.expenses.size
    => 1
    >> ili.expenses_count
    => 1
    >> ili.expenses.count
      SQL (0.3ms)   SELECT count(*) AS count_all FROM "expenses" WHERE ("expenses".invoice_line_item_id = 7) 
    => 1
    >>
    

    October 8th, 2009 @ 08:31 AM

  2. subimage
    subimage

    @Mark - read the original bug report. You missed the intent. It works when you use...

    
    ili.expenses << Expense.new
    

    What doesn't work is when you use...

    
    expense = Expense.create
    ili.expenses << expense
    

    However if you remove the :order option then re-run the above code it does work for the already existing expense.

    October 8th, 2009 @ 08:41 AM

  3. Rohit Arondekar
    Rohit Arondekar
    • State changed from new to stale
    • Importance changed from to

    Marking ticket as stale. If this is still an issue please leave a comment with suggested changes, creating a patch with tests, rebasing an existing patch or just confirming the issue on a latest release or master/branches.

    October 6th, 2010 @ 06:38 AM

  4. Jeff Kreeftmeijer