Skip to content

Commit

Permalink
Support Rails 6.1 ActiveModel::Errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Saverio Trioni authored and rewritten committed Sep 20, 2021
1 parent c31c249 commit 6f90086
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 41 deletions.
6 changes: 3 additions & 3 deletions granite.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ Gem::Specification.new do |s|
s.files = `git ls-files`.split("\n").grep(/\A(app|lib|config|LICENSE)/)
s.license = 'MIT'

s.add_runtime_dependency 'actionpack', '>= 5.1', '< 6.1'
s.add_runtime_dependency 'actionpack', '>= 5.1', '< 7'
s.add_runtime_dependency 'active_data', '~> 1.1.5'
s.add_runtime_dependency 'activesupport', '>= 5.1', '< 6.1'
s.add_runtime_dependency 'activesupport', '>= 5.1', '< 7'
s.add_runtime_dependency 'memoist', '~> 0.16'

s.add_development_dependency 'activerecord', '>= 5.0', '< 6.1'
s.add_development_dependency 'activerecord', '>= 5.0', '< 7'
s.add_development_dependency 'capybara', '~> 2.18'
s.add_development_dependency 'fuubar', '~> 2.0'
s.add_development_dependency 'pg', '< 2'
Expand Down
2 changes: 2 additions & 0 deletions lib/granite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
require 'granite/context'
require 'granite/util'

require 'granite/extensions/active_data'

module Granite
def self.config
Granite::Config.instance
Expand Down
12 changes: 3 additions & 9 deletions lib/granite/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,15 @@ def assign_attributes(attributes)
prepend AssignAttributes

handle_exception ActiveRecord::RecordInvalid do |e|
errors.messages.deep_merge!(e.record.errors.messages) do |_, this, other|
(this + other).uniq
end
errors.merge!(e.record.errors)
end

handle_exception ActiveData::ValidationError do |e|
errors.messages.deep_merge!(e.model.errors.messages) do |_, this, other|
(this + other).uniq
end
errors.merge!(e.model.errors)
end

handle_exception Granite::Action::ValidationError do |e|
errors.messages.deep_merge!(e.action.errors.messages) do |_, this, other|
(this + other).uniq
end
errors.merge!(e.action.errors)
end

# Almost the same as Dirty `#changed?` method, but
Expand Down
13 changes: 12 additions & 1 deletion lib/granite/action/preconditions/embedded_precondition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,20 @@ def _execute(context)
def decline_action(context, action)
return if action.satisfy_preconditions?

action.errors[:base].each { |error| context.errors.add(:base, error) }
merge_errors(context.errors, action.errors)

action.failed_preconditions.each { |error| context.failed_preconditions << error }
end

def merge_errors(target, source)
if source.respond_to?(:where)
# ActiveModel::Errors from version 6.1
source.where(:base).each { |error| target.import(error) }
else
# ActiveModel::Errors until version 6.0
source[:base].each { |error| target.add(:base, error) }
end
end
end
end
end
Expand Down
40 changes: 40 additions & 0 deletions lib/granite/extensions/active_data.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'active_data/model/validations/nested'

module Granite
module Extensions
module ActiveData
# ActiveModel::Errors 6.1 compatibility
module NestedValidatorCompatibility
extend ActiveSupport::Concern

module ClassMethods
def validate_nested(record, name, value, &block)
return super unless record.errors.respond_to?(:import)

validate_nested_with_import(record, name, value, &block)
end

private

def validate_nested_with_import(record, name, value)
if value.is_a?(Enumerable)
value.each.with_index do |object, i|
if yield(object)
object.errors.each do |error|
record.errors.import(error, attribute: "#{name}.#{i}.#{error.attribute}")
end
end
end
elsif value && yield(value)
value.errors.each do |error|
record.errors.import(error, attribute: "#{name}.#{error.attribute}")
end
end
end
end
end
end
end
end

ActiveData::Model::Validations::NestedValidator.prepend Granite::Extensions::ActiveData::NestedValidatorCompatibility
6 changes: 3 additions & 3 deletions spec/lib/granite/action/performing_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def execute_perform!(*)
let(:action) { Action.new(user, login: '') }

specify { expect(action.perform).to eq(false) }
specify { expect { action.perform }.to change { action.errors.messages }.to(base: [match('Base error message')]) }
specify { expect { action.perform }.to change { action.errors.messages }.to(base: ['Base error message']) }
specify { expect { action.perform }.not_to change { user.reload.email } }
end

Expand Down Expand Up @@ -236,7 +236,7 @@ def execute_perform!(*)
specify do
expect { action.perform! }
.to raise_error(Granite::Action::ValidationError)
.and change { action.errors.messages }.to(base: [match('Base error message')])
.and change { action.errors.messages }.to(base: ['Base error message'])
.and not_change { user.reload.email }
end
end
Expand Down Expand Up @@ -347,7 +347,7 @@ def execute_perform!(*)
let(:action) { Action.new(user, login: '') }

specify { expect { action.try_perform! }.not_to raise_error }
specify { expect { action.try_perform! }.to change { action.errors.messages }.to(base: [match('Base error message')]) }
specify { expect { action.try_perform! }.to change { action.errors.messages }.to(base: ['Base error message']) }
specify { expect { action.try_perform! }.not_to change { user.reload.email } }
end

Expand Down
2 changes: 1 addition & 1 deletion spec/lib/granite/action/preconditions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
let(:action) { Action.new(title: 'Delphi') }
specify do
expect { action.valid? }.to change { action.errors.messages }
.to(base: match_array(['Wrong title']))
.to(base: ['Wrong title'])
end
end

Expand Down
6 changes: 3 additions & 3 deletions spec/lib/granite/action_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
private

def execute_perform!(*)
errors.messages[:email] = ['custom error']
errors.add(:email, 'custom error')
DummyUser.new(attributes).validate!
end
end
Expand Down Expand Up @@ -69,7 +69,7 @@ def execute_perform!(*)
private

def execute_perform!(*)
errors.messages[:email] = ['custom error']
errors.add(:email, 'custom error')
DummyUser.new(attributes).validate!
end
end
Expand All @@ -94,7 +94,7 @@ def execute_perform!(*)
private

def execute_perform!(*)
errors.messages[:email] = ['custom error']
errors.add(:email, 'custom error')
NestedAction.new(attributes).perform!
end
end
Expand Down
22 changes: 1 addition & 21 deletions spec/lib/granite/rspec/raise_validation_error_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,7 @@ def execute_perform!(*)
let(:action) { Action.new(raise_error: true) }

specify do
expect do
expect { action.perform! }.not_to raise_validation_error.of_type(:some_error)
end.to fail_with('expected not to raise validation error on attribute :base of type :some_error')
end

specify do
expect do
expect { action.perform! }.to raise_validation_error.of_type(:some_error2)
end.to fail_with('expected to raise validation error on attribute :base of type :some_error2, but raised {:base=>[{:error=>:some_error}]}')
end

specify do
expect do
expect { action.perform! }.to raise_validation_error.on_attribute(:raise_error)
end.to fail_with('expected to raise validation error on attribute :raise_error, but raised {:base=>[{:error=>:some_error}], :raise_error=>[]}')
end

specify do
expect do
expect { action.perform! }.to raise_validation_error.on_attribute(:raise_error).of_type(:some_error)
end.to fail_with('expected to raise validation error on attribute :raise_error of type :some_error, but raised {:base=>[{:error=>:some_error}], :raise_error=>[]}')
expect { action.perform! }.to raise_validation_error.on_attribute(:base).of_type(:some_error)
end
end
end

0 comments on commit 6f90086

Please sign in to comment.