Has_many removal: through association does not change the model updated_at attribute

It’s not easy for me to get the updated update_at column to update the casino model, which has all kinds of amenities through CasinoAmenity. The casino updated_at column is updated properly when adding amenities, but not when they are removed.

Here are 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 start time of update_at.

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

Adding amenities 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">] 

Confirmation that the association has been stored in 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 see that the update_at time for this casino has changed, as expected.

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

Now remove this service from the casino.

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

Now make sure it hits the database perfectly

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

Now you can 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, this is the same as before we removed the amenities from the casino. I also tried the before_destroy filter on AmenityCasino to touch the casino, but that didn't seem to help.

I would like to hear if there are any solutions here. If that matters, I use ActiveAdmin to manage everything.

Rails Version - 3.2.11

+7
source share
2 answers

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

It should be like this:

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

This will not solve the problem here. Referring to this (somewhat old) SO answer , it seems that the problem is that the connection table entries are deleted rather than destroyed and deleted, do not run the touch method, therefore updated_at not updated.

To get around this, you can add the :after_remove parameter to your association and pass the proc , which calls touch in the model itself:

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

I 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 the timestamp has changed. You will need to do the same for your Amenity model if you want the updated_at attribute to updated_at updated on this as well.

+9
source

Before talking about this, I should note that I am not sure if this is true in Rails 3.2, but I am sure that it is valid in Rails 4 +

Now I know that this was answered, but only for future reference instead

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

you can use the destroy_all method, which destroys all join_model and touch association entries (if you have an option like in your example), and also execute the appropriate callbacks (for destroy ) on join_model (in the AmenityCasino example)

 > Casino.find(5).amenities.destroy_all 
0
source

All Articles