This project is archived and is in readonly mode.

#3344 ✓stale
subimage

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

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

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
>>

Comments and changes to this ticket

  • Mark Turner

    Mark Turner October 8th, 2009 @ 08:31 AM

    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
    >>
    
  • subimage

    subimage October 8th, 2009 @ 08:41 AM

    @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.

  • Rohit Arondekar

    Rohit Arondekar October 6th, 2010 @ 06:38 AM

    • 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.

  • Jeff Kreeftmeijer

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages