diff --git a/CHANGELOG b/CHANGELOG index e8f4418..259f2f5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ === master +* Ignore unique constraint violations when adding associated objects in mtm_update (jeremyevans) + * Handle search fields that cannot be typecast correctly by returning no results (jeremyevans) === 1.9.1 (2019-07-22) diff --git a/lib/autoforme/models/sequel.rb b/lib/autoforme/models/sequel.rb index 0f01aa8..85b8e75 100644 --- a/lib/autoforme/models/sequel.rb +++ b/lib/autoforme/models/sequel.rb @@ -300,7 +300,11 @@ def mtm_update(request, assoc, obj, add, remove) ids.each do |id| next if id.to_s.empty? ret = assoc_class ? assoc_class.with_pk(:association, request, id) : obj.send(:_apply_association_options, ref, ref.associated_class.dataset.clone).with_pk!(id) - obj.send(meth, ret) + begin + model.db.transaction(:savepoint=>true){obj.send(meth, ret)} + rescue S::UniqueConstraintViolation + # Already added, safe to ignore + end end end end diff --git a/spec/mtm_spec.rb b/spec/mtm_spec.rb index 83a1998..1268edf 100644 --- a/spec/mtm_spec.rb +++ b/spec/mtm_spec.rb @@ -507,3 +507,67 @@ def req.xhr?; action_type == 'mtm_update' end page.all('select')[1].all('option').map{|s| s.text}.must_equal ["Album2", "Album3"] end end + +describe AutoForme do + before(:all) do + db_setup(:artists=>[[:name, :string]], :albums=>[[:name, :string]], :albums_artists=>proc{column :album_id, :integer, :table=>:albums; column :artist_id, :integer, :table=>:artists; primary_key [:album_id, :artist_id]}) + model_setup(:Artist=>[:artists, [[:many_to_many, :albums]]], :Album=>[:albums, [[:many_to_many, :artists]]]) + end + after(:all) do + Object.send(:remove_const, :Album) + Object.send(:remove_const, :Artist) + end + + it "should handle unique constraint violation errors when adding associated objects" do + app_setup do + model Artist do + mtm_associations :albums + end + model Album + end + + artist = Artist.create(:name=>'Artist1') + album = Album.create(:name=>'Album1') + + visit("/Artist/mtm_edit") + page.title.must_equal 'Artist - Many To Many Edit' + select("Artist1") + click_button "Edit" + + find('h2').text.must_equal 'Edit Albums for Artist1' + page.all('select')[0].all('option').map{|s| s.text}.must_equal ["Album1"] + page.all('select')[1].all('option').map{|s| s.text}.must_equal [] + select("Album1", :from=>"Associate With") + artist.add_album(album) + click_button "Update" + page.html.must_include 'Updated albums association for Artist' + Artist.first.albums.map{|x| x.name}.must_equal %w'Album1' + end + + it "should handle unique constraint violation errors when adding associated objects" do + app_setup do + model Artist do + mtm_associations :albums + end + model Album + end + + artist = Artist.create(:name=>'Artist1') + album = Album.create(:name=>'Album1') + artist.add_album(album) + + visit("/Artist/mtm_edit") + page.title.must_equal 'Artist - Many To Many Edit' + select("Artist1") + click_button "Edit" + + find('h2').text.must_equal 'Edit Albums for Artist1' + page.all('select')[0].all('option').map{|s| s.text}.must_equal [] + page.all('select')[1].all('option').map{|s| s.text}.must_equal ["Album1"] + select("Album1", :from=>"Disassociate From") + artist.remove_album(album) + click_button "Update" + page.html.must_include 'Updated albums association for Artist' + Artist.first.albums.map{|x| x.name}.must_equal [] + end +end