Skip to content

Commit

Permalink
Introduces instance level skip validation option.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nitin-Salunke committed Jul 30, 2019
1 parent f31535c commit bcf9183
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 0 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,13 @@ class Job < ActiveRecord::Base
end
```

Also You can skip the validation at instance level with `some_event_name_without_validation!` method.
With this you have the flexibility of having validation for all your transitions by default and then skip it wherever required.
Please not that only update column will be updated as mentioned in the above example.
<br/>
<br/>
<br/>

If you want to make sure that the _AASM_ column for storing the state is not directly assigned,
configure _AASM_ to not allow direct assignment, like this:

Expand Down
17 changes: 17 additions & 0 deletions lib/aasm/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ def event(name, options={}, &block)
aasm_fire_event(aasm_name, event, {:persist => false}, *args, &block)
end

skip_instance_level_validation(event, name, aasm_name, klass)

# Create aliases for the event methods. Keep the old names to maintain backwards compatibility.
if namespace?
klass.send(:alias_method, "may_#{name}_#{namespace}?", "may_#{name}?")
Expand Down Expand Up @@ -248,5 +250,20 @@ def interpret_state_args(args)
end
end

def skip_instance_level_validation(event, name, aasm_name, klass)
# Overrides the skip_validation config for an instance (If skip validation is set to false in original config) and
# restores it back to the original value after the event is fired.
safely_define_method klass, "#{name}_without_validation!", ->(*args, &block) do
original_config = AASM::StateMachineStore.fetch(self.class, true).machine(aasm_name).config.skip_validation_on_save
begin
AASM::StateMachineStore.fetch(self.class, true).machine(aasm_name).config.skip_validation_on_save = true unless original_config
aasm(aasm_name).current_event = :"#{name}!"
aasm_fire_event(aasm_name, event, {:persist => true}, *args, &block)
ensure
AASM::StateMachineStore.fetch(self.class, true).machine(aasm_name).config.skip_validation_on_save = original_config
end
end
end

end
end
5 changes: 5 additions & 0 deletions spec/database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,9 @@
t.string "search"
t.string "sync"
end

ActiveRecord::Migration.create_table "instance_level_skip_validation_examples", :force => true do |t|
t.string "state"
t.string "some_string"
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class InstanceLevelSkipValidationExample < ActiveRecord::Base
include AASM

aasm :state do
state :new, :initial => true
state :draft
state :complete

event :set_draft do
transitions from: :new, to: :draft
end

event :complete do
transitions from: %i[draft new], to: :complete
end
end

validates :some_string, presence: true
end
22 changes: 22 additions & 0 deletions spec/unit/persistence/active_record_persistence_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -748,4 +748,26 @@
expect { job.run }.to raise_error(AASM::InvalidTransition)
end
end

describe 'testing the instance_level skip validation with _without_validation method' do
let(:example) do
obj = InstanceLevelSkipValidationExample.new(state: 'new')
obj.save(validate: false)
obj
end

it 'should be able to change the state with invalid record' do
expect(example.valid?).to be_falsey
expect(example.complete!).to be_falsey
expect(example.complete_without_validation!).to be_truthy
expect(example.state).to eq('complete')
end

it 'shouldn\'t affect the behaviour of existing method after calling _without_validation method' do
expect(example.set_draft!).to be_falsey
expect(example.set_draft_without_validation!).to be_truthy
expect(example.state).to eq('draft')
expect(example.complete!).to be_falsey
end
end
end

0 comments on commit bcf9183

Please sign in to comment.