diff --git a/lib/mongoid/persistable/updatable.rb b/lib/mongoid/persistable/updatable.rb index 9dc5aeeaf7..34b5d2a777 100644 --- a/lib/mongoid/persistable/updatable.rb +++ b/lib/mongoid/persistable/updatable.rb @@ -38,8 +38,16 @@ def update_attribute(name, value) # # @return [ true | false ] True if validation passed, false if not. def update(attributes = {}) - assign_attributes(attributes) - save + self.class.with_session do |session| + session.with_transaction do + assign_attributes(attributes) + save.tap do |result| + session.abort_transaction unless result + end + end + end + rescue StandardError => e + false end alias :update_attributes :update diff --git a/spec/integration/validations_spec.rb b/spec/integration/validations_spec.rb new file mode 100644 index 0000000000..8f5d2989df --- /dev/null +++ b/spec/integration/validations_spec.rb @@ -0,0 +1,41 @@ +# rubocop:todo all +# frozen_string_literal: true + +require 'spec_helper' +require_relative './validations_spec_models' + +describe 'validations' do + + context 'when validating presence of has_and_belongs_to_many association' do + let(:company) { ValidationsSpecModels::Company.create! } + let(:client) { ValidationsSpecModels::Client.create!(companies: [company]) } + + context 'when updating the association' do + it 'raises an error' do + expect { client.update!(companies: []) }.to raise_error(Mongoid::Errors::Validations) + end + + it 'does not persist the changes' do + client.update!(companies: []) rescue nil + expect(client.reload.companies).not_to be_empty + end + end + end + + + context 'when validating presence of has_many association' do + let(:apartment) { ValidationsSpecModels::Apartment.create! } + let(:building) { ValidationsSpecModels::Building.create!(apartments: [apartment]) } + + context 'when updating the association' do + it 'raises an error' do + expect { building.update!(apartments: []) }.to raise_error(Mongoid::Errors::Validations) + end + + it 'does not persist the changes' do + building.update!(apartments: []) rescue nil + expect(building.reload.apartments).not_to be_empty + end + end + end +end diff --git a/spec/integration/validations_spec_models.rb b/spec/integration/validations_spec_models.rb new file mode 100644 index 0000000000..0aaa14502e --- /dev/null +++ b/spec/integration/validations_spec_models.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module ValidationsSpecModels + class Company + include Mongoid::Document + end + + class Client + include Mongoid::Document + + has_and_belongs_to_many :companies, class_name: 'ValidationsSpecModels::Company' + validates :companies, presence: true + end + + class Building + include Mongoid::Document + has_many :apartments, class_name: 'ValidationsSpecModels::Apartment' + validates :apartments, presence: true + end + + class Apartment + include Mongoid::Document + belongs_to :building, class_name: 'ValidationsSpecModels::Building' + end +end