Habtm Duplicate Records

HABTM duplicate records

You should use database-level validation:

#new_migration
add_index :games_themes, [:game_id, :theme_id], :unique => true

HABTM

This will prevent you saving any duplicate data in the database. Takes the burden off Rails & ensures you only have game or theme. The problem is because HABTM doesn't have a model, there's no validation you can perform in Rails, meaning you need to make it db-level

As mentioned in the comments, this means you'll have to handle the exceptions raised from the db like this:

#app/controllers/games_controller.rb
def create
#creation stuff here
if @game.save
#successful save
else
#capture errors
end
end

has_and_belongs_to_many creating duplicate entries in model

First note, that has_and_belongs_to_many create a many to many relationship with the party that it connects. Therefore you can have two objects related to each other in this fashion:

issues.rb

class Issue < ActiveRecord::Base
has_and_belongs_to_many :labels
end

labels.rb

class Label < ActiveRecord::Base
has_and_belongs_to_many :issues
end

See section: 2.6 The has_and_belongs_to_many Association of this: http://guides.rubyonrails.org/association_basics.html

In the migration you create the join table, but you do not need to model it.

Now the way you are doing your create will always create a new label.

There is a difference in these two statements:

issue.labels.find_or_create_by(name: 'bug')

and

issue.labels << Label.find_or_create_by(name: 'bug')

The former looks inside the related labels to the issue and creates one if it doesn't exist. For instance, it only queries what issue.labels would return. Therefore when it can not find a related label to the issue with that name, it creates one. Now the latter query does this differently. It looks within the Labels model and says "is there any labels in here with the name 'bug'?" if there are, it finds that label and associates that a label of the issue. If not, it creates a new label before associating it with the issue.

In your case, the latter method will return the result you are looking for.

---- Sub question from Comments about deleting -----

has_and_belongs_to relationships are a 3 table join. When you call:

issue.labels.first 

You are listing the first object within the labels collection. This object is a Label, not a join. Removing this, removes the actual object Label that is references in your join table.

issue.labels.first.delete
issue.labels.first.destroy

Both of these are equivalent to calling, assuming there was only one label in your collection (both remove the object, destroy triggers the callbacks):

Label.first.delete
Label.first.destroy

This is not what you are trying to achieve. What you need to do is call is this:

label = Label.first
issue.labels.delete(label)

This leaves the label as is, and just removes the association from the join table.

has_and_belongs_to_many, avoiding dupes in the join table

I worked around this by creating a before_save filter that fixes stuff up.

class Post < ActiveRecord::Base 
has_and_belongs_to_many :tags
before_save :fix_tags

def tag_list= (tag_list)
self.tags.clear
tag_list.strip.split(' ').each do
self.tags.build(:name => tag)
end
end

def fix_tags
if self.tags.loaded?
new_tags = []
self.tags.each do |tag|
if existing = Tag.find_by_name(tag.name)
new_tags << existing
else
new_tags << tag
end
end

self.tags = new_tags
end
end

end

It could be slightly optimised to work in batches with the tags, also it may need some slightly better transactional support.

Ruby on Rails Active Admin - Duplicate Records showing for HABTM

has_and_belongs_to_many accepts a :uniq option which ensures that only uniq records will be returned. Setting this in your model should do the trick.

class MyModel
has_and_belongs_to_many :things, :uniq => true
end

Rails nested form on HABTM: how to prevent duplicate entry?

in employee.rb:

before_save :get_phonenumbers

def get_phonenumbers
self.phonenumbers = self.phonenumbers.collect do |phonenumber|
Phonenumber.find_or_create_by_number(phonenumber.number)
end
end

I have found its working

Removing one of the many duplicate entries in a habtm relationship?

You should really be using a has_many :through relationship here. Otherwise, yes, the only way to accomplish your goal is to create a method to count the current number of a particular stone, delete them all, then add N - 1 stones back.

class Bowl << ActiveRecord::Base
has_and_belongs_to_many :stones

def remove_stone(stone, count = 1)
current_stones = self.stones.find(:all, :conditions => {:stone_id => stone.id})
self.stones.delete(stone)
(current_stones.size - count).times { self.stones << stone }
end
end

Remember that LIMIT clauses are not supported in DELETE statements so there really is no way to accomplish what you want in SQL without some sort of other identifier in your table.

(MySQL actually does support DELETE ... LIMIT 1 but AFAIK ActiveRecord won't do that for you. You'd need to execute raw SQL.)

Rails will_paginate shows duplicates on HABTM models

I think I ran into this problem before. Try adding this to your query:

.group("id")

It's not a bug in will_paginate, because all that does is take the data it gives you and paginates it in the view. The solution lies in the data you provide it.



Related Topics



Leave a reply



Submit