Does anyone have an efficient/elegant way to prevent duplicate inserts when using a has_many :through relationship. So I have something like this: class User < ActiveRecord::Base has_many :favorite_teams has_many :teams, :through => :favorite_teams end class FavoriteTeams < ActiveRecord::Base belongs_to :user belongs_to :team end class Teams < ActiveRecord::Base has_many :favorite_teams has_many :users, :through => :favorite_teams end If one user creates a team like ''nationals'' it will create the record in the teams table and the associated favorite_teams table. That''s fine. Now, in my case if another user comes along and has the same favorite team (''nationals'') I would rather not have the duplicate insert into the teams table. I just want the association record created in favorite_teams. On top of that I need to be able to handle deletion in a particular way. If one user removes ''nationals'' as their favorite team I need to know if any other user has that favorite team, if so then it should remain and only the association for that user should be deleted. If no other user has that favorite team then I need both records deleted. -- Posted via http://www.ruby-forum.com/.
Josh Susser
2006-Jul-04 02:22 UTC
[Rails] Re: prevent duplicate inserts with has_many :through ??
Dave wrote:> Does anyone have an efficient/elegant way to prevent duplicate inserts > when using a has_many :through relationship. > > So I have something like this: > > class User < ActiveRecord::Base > has_many :favorite_teams > has_many :teams, :through => :favorite_teams > end > > class FavoriteTeams < ActiveRecord::Base > belongs_to :user > belongs_to :team > end > > class Teams < ActiveRecord::Base > has_many :favorite_teams > has_many :users, :through => :favorite_teams > end > > > If one user creates a team like ''nationals'' it will create the record in > the teams table and the associated favorite_teams table. That''s fine. > > Now, in my case if another user comes along and has the same favorite > team (''nationals'') I would rather not have the duplicate insert into the > teams table. I just want the association record created in > favorite_teams. > > On top of that I need to be able to handle deletion in a particular way. > If one user removes ''nationals'' as their favorite team I need to know if > any other user has that favorite team, if so then it should remain and > only the association for that user should be deleted. If no other user > has that favorite team then I need both records deleted.>From your opening sentence I thought you were going to ask how to avoidduplicate rows in the join model table itself. This is actually a more interesting problem I think :-) The problem you''re trying to solve is what ActiveRecord lifecycle callbacks are for. Check out chapter 15 of AWDR for a good explanation. class User < ActiveRecord::Base has_many :favorite_teams, :dependent => :destroy has_many :teams, :through => :favorite_teams end class FavoriteTeam < ActiveRecord::Base belongs_to :user belongs_to :team after_create { |fave| fave.team.ref_up } after_destroy { |fave| fave.team.ref_down } end Unfortunately, the counter_cache feature won''t work with join models because has_many :through associations don''t work like regular has_many collections. (see http://blog.hasmanythrough.com/articles/read/150 for more background) But you can still put a ref count in the Team class to track how many Favorites reference it. Start it at 1 when created (since it gets created with an existing FavoriteTeam). Use #ref_up and #ref_down to increment and decrement the count. When it drops to zero, it can self-destruct. If you don''t want to maintain the refcount, you can lose the #ref_up method (and the after_create callback in FavoriteTeam) and just have #ref_down query for FavoriteTeam records to see if it''s referenced; when there are no records with a ref it can self-destruct. Not sure which way you should go. I''ll leave it up to you to figure out which approach works better for your system. By the way, Rails convention is for model class names to be singular, tables plural. good luck! -- Josh Susser http://blog.hasmanythrough.com -- Posted via http://www.ruby-forum.com/.