Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing has_many :through association doesn't change model's updated_at attribute

I'm having a hard time getting the updated_at column to update on a Casino model that has_many Amenities through CasinoAmenity. The casino's updated_at column gets updated properly when adding amenities, but not when removing them.

Here's my (simplified) models:

casino.rb

class Casino < ActiveRecord::Base
  has_many :amenity_casino, :dependent => :destroy
  has_many :amenities, :through => :amenity_casino
end

amenity_casino.rb

class AmenityCasino < ActiveRecord::Base
  belongs_to :casino, :touch => true
  belongs_to :amenity, :touch => true
end

amenity.rb

class Amenity < ActiveRecord::Base
  has_many :amenity_casinos, :dependent => :destroy
  has_many :casinos, :through => :amenity_casinos
end

Now to the console. Checking the initial updated_at time.

> Casino.find(5).updated_at
=> Wed, 30 Jan 2013 00:30:04 UTC +00:00

Adding an amenity to the casino.

> Casino.find(5).amenities << Amenity.first
=> [#<Amenity id: 1, name: "asdf", weight: "", created_at: "2012-11-10 02:29:14", updated_at: "2013-01-30 01:29:14", description: "asdf">]

Confirming the association was saved to the database

> Casino.find(5).amenities
=> [#<Amenity id: 1, name: "asdf", weight: "", created_at: "2012-11-10 02:29:14", updated_at: "2013-01-30 01:29:14", description: "asdf">]

We can see that the updated_at time for that casino has changed, as expected.

> Casino.find(5).updated_at
=> Wed, 30 Jan 2013 01:29:14 UTC +00:00

Now let's remove that amenity from the casino.

> Casino.find(5).amenities = []
=> []

Now making sure it hit the database fine

> Casino.find(5).amenities
=> []

Now let's check the updated_at column for the casino...

> Casino.find(5).updated_at
=> Wed, 30 Jan 2013 01:29:14 UTC +00:00

As you can see, it's the same as before we removed the amenity from the casino. I've also tried a before_destroy filter on AmenityCasino to touch the casino, but that didn't seem to do the trick.

I'd love to hear if anyone has any solutions here. If it matters, I'm using ActiveAdmin to manage everything.

Rails version is 3.2.11

like image 903
RFC1337 Avatar asked Jan 30 '13 01:01

RFC1337


1 Answers

First, you're missing an 's' at the end of amenity_casino in two places in your Casino model.

Should be like this:

class Casino < ActiveRecord::Base
  has_many :amenity_casinos, :dependent => :destroy
  has_many :amenities, :through => :amenity_casinos
end

That won't solve the problem here, though. Referring to this (somewhat old) SO answer, it looks like the problem is that join table entries are deleted, not destroyed, and deletes don't trigger the touch method, thus updated_at is not updated.

To get around that, you can add an :after_remove option to your association and pass a proc which calls touch on the model itself:

has_many :amenity_casinos, :dependent => :destroy
has_many :amenities, :through => :amenity_casinos,\
         :after_remove => proc { |a| a.touch }

I've tested this and it seems to work:

Casino.find(5).updated_at
#=> Wed, 30 Jan 2013 03:21:29 UTC +00:00
Casino.find(5).amenities << Amenity.first
#=> [#<Amenity id: 1, name: nil, created_at: "2013-01-30 02:48:49", updated_at: "2013-01-30 03:25:23">]
Casino.find(5).amenities
#=> [#<Amenity id: 1, name: nil, created_at: "2013-01-30 02:48:49", updated_at: "2013-01-30 03:25:23">]
Casino.find(5).updated_at
#=> Wed, 30 Jan 2013 03:25:23 UTC +00:00
Casino.find(5).amenities = []
#=> []
Casino.find(5).updated_at
#=> Wed, 30 Jan 2013 03:27:33 UTC +00:00

You can see that the timestamp has changed. You'll have to do the same thing for your Amenity model if you want to have the updated_at attribute updated on that one as well.

like image 57
Chris Salzberg Avatar answered Oct 23 '22 01:10

Chris Salzberg