FeeFighters/samurai-client-ruby — Issue #2: PaymentMethod has_errors?==false when errors exist
Author: jkrall
Created: 2011-11-20 20:58:28+00:00
State: open

I first noticed that PaymentMethod.has_errors? was returning false when it should return true:

```
% rails console

irb(main):001:0> pm = Samurai::PaymentMethod.find "a58699ccba30149b88ab1d0f"
irb(main):002:0> pm.has_errors?
=> false
irb(main):003:0> pm.errors.empty?
=> true
```

However:

```
irb(main):004:0> pm.errors.count
=> 5
```

Adding my own error provided the key clue:

```
irb(main):005:0> pm.errors.add(:foo, "Foobar")
=> ["Foobar"]
irb(main):006:0> pm.errors.count
=> 6
irb(main):007:0> pm.errors.empty?
=> false
irb(main):008:0> pm.has_errors?
=> true
```
Samurai::Base.has_errors? delegates to errors.empty?:

```
def has_errors?
respond_to?(:errors) && !errors.empty?
end
```

And ActiveResource::Errors implements empty? as:

```
def empty?
all? { |k, v| v && v.empty? }
end
```

PaymentMethod errors are added via PaymentMethod.process_response_errors:

```
def process_response_errors
if respond_to?(:messages) && self.messages
self.messages.each do |message|
self.errors.add message.context, message.description
end
end
end
```

where the message (v, in the ActiveRecord:Errors.empty? context) is returned by calling message.description:

```
def description
_key = [subclass, context, key].join(' ')
self.class.response_mappings[_key] || ''
end
```

But for my PaymentMethod object, the constructed keys do not exist in Samurai::Message.DEFAULT_RESPONSE_MAPPINGS:

```
irb(main):009:0> pm.messages.each do |m|
irb(main):010:1* puts [m.subclass, m.context, m.key].join(' ')
irb(main):011:1> end
error input.card_number not_numeric
error input.card_number too_short
error input.cvv too_short
error input.cvv not_numeric
error input.card_number is_blank
```

Thus, message.description returns an empty string:

```
irb(main):012:0> pm.messages.each do |m|
irb(main):013:1* puts "message.description = '#{m.description}'"
irb(main):014:1> end
message.description = ''
message.description = ''
message.description = ''
message.description = ''
message.description = ''
```

so ultimately PaymentMethod.has_errors? returns false.

As an aside, some of the above errors seem like they ought to be filtered, to avoid inundating a user with redundant error messages. For example, even though a blank card number might technically imply not_numeric and too_short, reporting only a blank card number is probably sufficient.