Deleting records using nested attributes decreases the counter cache twice

Hi guys,

I have these models:

class Compra < ActiveRecord::Base   belongs_to :proveedor   has_many :detalle_de_compras   has_many :lotes, :through => :detalle_de_compras

  accepts_nested_attributes_for :detalle_de_compras, :allow_destroy => true

  def nombre_proveedor     self.proveedor.try(:nombre)   end end

class DetalleDeCompra < ActiveRecord::Base   belongs_to :compra, :counter_cache => true   belongs_to :lote

  accepts_nested_attributes_for :lote end

The problem is that when I delete a "DetalleDeCompra" through an update to "Compra" using nested attributes (with the _delete param set to something that evaluates to true) the counter cache is decreased twice.

I don't know if it's worth mentioning that I'm sending data for a 2 level deep nested structure. This is the deepest model I'm using:

class Lote < ActiveRecord::Base   belongs_to :estado_del_lote   belongs_to :producto   has_one :detalle_de_compra   has_one :compra, :through => :detalle_de_compra

  def nombre_producto     self.producto.try(:nombre)   end

  def nombre_estado_del_lote     self.estado_del_lote.try(:nombre)   end

  def fecha_compra     self.compra.try(:fecha)   end end

Any ideas on what's wrong here?

P.S. Here is the migration to the model holding the counter cache:

class CreateCompras < ActiveRecord::Migration   def self.up     create_table :compras do |t|       t.integer :proveedor_id       t.date :fecha       t.date :fecha_de_pago       t.string :condicion_de_pago       t.integer :detalle_de_compras_count, :default => 0

      t.timestamps     end   end

  def self.down     drop_table :compras   end end

Hi, please can you specify which version of Rails are you currently using, and an example of the code that causes your problem?

I tried to reproduce it with: compra.update_attributes :detalle_de_compras_attributes => [{:id => 953125641, :_delete => true}]

but works fine for me, it decrements the counter once.

Cheers, Luca

I'm using Rails 2.3.2, on Ubuntu 8.10.

Ok, here is a capture of the "params" sent to create a record, with the nested params: # URL: http://localhost:3000/compras/create # Compra params compra[fecha] 2009-06-04 compra[proveedor_id] 1 compra[condicion_de_pago] 15 dias compra[fecha_de_pago] 2009-06-18

# First nested model, DetalleDeCompra params compra[detalle_de_compras_attributes][0][id] compra[detalle_de_compras_attributes][0][cantidad] 10 compra[detalle_de_compras_attributes][0][precio_unitario] 123

# Second nested model, Lote params compra[detalle_de_compras_attributes][0][lote_attributes][cantidad] 10 compra[detalle_de_compras_attributes][0][lote_attributes] [estado_del_lote_id] 2 compra[detalle_de_compras_attributes][0][lote_attributes][producto_id] 5

Then the params to delete that DetalleDeCompra instance that triggers the problem: # URL: http://localhost:3000/compras/update/3 compra[fecha] 2009-06-04 compra[proveedor_id] 1 compra[condicion_de_pago] 15 dias compra[fecha_de_pago] 2009-06-18

compra[detalle_de_compras_attributes][0][id] 8 compra[detalle_de_compras_attributes][0][cantidad] 10 compra[detalle_de_compras_attributes][0][precio_unitario] 123 compra[detalle_de_compras_attributes][0][_delete] true

compra[detalle_de_compras_attributes][0][lote_attributes][cantidad] 10 compra[detalle_de_compras_attributes][0][lote_attributes] [estado_del_lote_id] 2 compra[detalle_de_compras_attributes][0][lote_attributes][producto_id] 5

And the code, is the same code that all controllers have in the Update action: @data = Compra.find(params[:id]) @data.update_attributes(params[compra]) @data.save

Best regards.

Ah!, forgot to mention that the count then goes from 1 record to -1 records.

Hi, just gave a look at your code, the problem is trivial: you shouldn't call both #update_attributes *and* #save, because they performs the same operation. The former is a syntax shortcut:

person.name = "luca" person.age = 26 person.save

# or

person.update_attributes :name => "luca", :age => 26

So, updating *twice* your record, the detalle de compras counter will be decreased assuming the value of -1.

Cheers, Luca

Ah! thank you a lot :slight_smile: Works flawless now.

Best regards.