Database tables look like so:
items:
+----+---------
| id | title
+----+---------
| 1 | Test 1
| 2 | Test 2
tags:
+----+---------+
| id | tag |
+----+---------+
| 1 | tag1 |
| 2 | tag2 |
items_tags:
+----+---------+--------+
| id | item_id | tag_id |
+----+---------+--------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
Models look like:
models/item.rb
class Item < ActiveRecord::Base
has_and_belongs_to_many :tags
def tags_s=(tags_s)
for tag in tags_s.split(' ')
self.tags.push(Tag.find_or_create_by_tag(tag))
end
end
def tags_s
tags.join(' ')
end
end
models/tag.rb
class Tag < ActiveRecord::Base
has_and_belongs_to_many :items
def to_s
return tag
end
end
On the console this happens:
>> newitem = Item.new
=> #<Item:0xb750ba74 @new_record=true, @attributes={"created_on"=>nil, "text"=>nil, "title"=>"", "updated_on"=>nil, "type"=>""}>
>> newitem.title = "console test"
=> "console test"
>> newitem.text = "test"
=> "test"
>> newitem.save
=> true
>> newitem
=> #<Item:0xb750ba74 @new_record=false, @new_record_before_save=true, @attributes={"created_on"=>Sun Nov 26 18:21:09 GMT 2006, "text"=>"test", "title"=>"console test", "updated_on"=>Sun Nov 26 18:21:09 GMT 2006, "type"=>"", "id"=>3}, @errors=#<ActiveRecord::Errors:0xb75067a4 @base=#<Item:0xb750ba74 ...>, @errors={}>>
>> newitem.tags_s=("tag2")
ActiveRecord::StatementInvalid: Mysql::Error: Duplicate entry '2' for key 1: INSERT INTO items_tags (`item_id`, `tag_id`, `id`) VALUES (3, 2, 2)
.... trace snipped ...
>> newitem.tags_s=("tag3")
=> "tag3"
That is, if the tag doesn't exist then this works fine, if it exists then for some reason it tries to add an entry to the join table with an id that already exists (looks like the id of the first entry which references the required tag). Why does it do this? It doesn't need to save an id at all as the database will generate it automatically. How can I fix it?