Skip to content

Commit

Permalink
Support #save(object, validate: false)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrykonchin committed Nov 1, 2024
1 parent 6ad9e13 commit 3f7e154
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 6 deletions.
14 changes: 8 additions & 6 deletions lib/dynamoid/transaction_write/save.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ def initialize(model, **options)
def on_registration
validate_model!

unless @valid = @model.valid?
if @options[:raise_error]
raise Dynamoid::Errors::DocumentNotValid, @model
else
@aborted = true
return
unless @options[:validate] == false
unless @valid = @model.valid?
if @options[:raise_error]
raise Dynamoid::Errors::DocumentNotValid, @model
else
@aborted = true
return
end
end
end

Expand Down
93 changes: 93 additions & 0 deletions spec/dynamoid/transaction_write/save_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,25 @@ def around_save_callback
expect(obj).to be_changed
end

context 'validate: false option' do
it 'persists an invalid model' do
obj = klass_with_validation.new(name: 'one')
expect(obj.valid?).to eql false

expect {
described_class.execute do |txn|
txn.save obj, validate: false
end
}.to change { klass_with_validation.count }.by(1)

obj_loaded = klass_with_validation.find(obj.id)
expect(obj_loaded.name).to eql 'one'

expect(obj).to be_persisted
expect(obj).not_to be_changed
end
end

it 'returns true when model valid' do
obj = klass_with_validation.new(name: 'oneone')
expect(obj.valid?).to eql true
Expand Down Expand Up @@ -420,6 +439,24 @@ def around_save_callback
expect(obj).to be_changed
end

context 'validate: false option' do
it 'persists an invalid model' do
obj = klass_with_validation.create!(name: 'oneone')
obj.name = 'one'
expect(obj.valid?).to eql false

described_class.execute do |txn|
txn.save obj, validate: false
end

obj_loaded = klass_with_validation.find(obj.id)
expect(obj_loaded.name).to eql 'one'

expect(obj).to be_persisted
expect(obj).not_to be_changed
end
end

it 'returns true when model valid' do
obj = klass_with_validation.create!(name: 'oneone')
obj.name = 'oneone [Updated]'
Expand Down Expand Up @@ -810,6 +847,45 @@ def around_create_callback
'run after_save')
expect(ScratchPad.recorded).to eql []
end

it 'skips *_validation callbacks when validate: false option specified and valid model' do
klass_with_callbacks = new_class do
before_validation { ScratchPad << 'run before_validation' }
after_validation { ScratchPad << 'run after_validation' }

field :name
validates :name, presence: true
end

ScratchPad.record []
klass_with_callbacks.create_table
obj = klass_with_callbacks.new(name: 'Alex')

described_class.execute do |txn|
txn.save obj, validate: false
end

expect(ScratchPad.recorded).to eql []
end

it 'skips *_validation callbacks when validate: false option specified and invalid model' do
klass_with_callbacks = new_class do
before_validation { ScratchPad << 'run before_validation' }
after_validation { ScratchPad << 'run after_validation' }

field :name
validates :name, presence: true
end
ScratchPad.record []
klass_with_callbacks.create_table
obj = klass_with_callbacks.new(name: '')

described_class.execute do |txn|
txn.save obj, validate: false
end

expect(ScratchPad.recorded).to eql []
end
end

context 'persisted model' do
Expand Down Expand Up @@ -1078,6 +1154,23 @@ def around_update_callback
}.to raise_error(Dynamoid::Errors::DocumentNotValid)
end

it 'persists an invalid model when validate: false option specified' do
obj = klass_with_validation.new(name: 'one')
expect(obj.valid?).to eql false

expect {
described_class.execute do |txn|
txn.save! obj, validate: false
end
}.to change { klass_with_validation.count }.by(1)

obj_loaded = klass_with_validation.find(obj.id)
expect(obj_loaded.name).to eql 'one'

expect(obj).to be_persisted
expect(obj).not_to be_changed
end

it 'rolls back the whole transaction when a model to be created is invalid' do
obj_invalid = klass_with_validation.new(name: 'one')
obj_valid = klass_with_validation.new(name: 'twotwo')
Expand Down

0 comments on commit 3f7e154

Please sign in to comment.