救援块未捕获引发的错误

时间:2019-08-23 10:53:05

标签: ruby-on-rails ruby error-handling actionmailer

使用动作邮件发送电子邮件时,我们遇到了生产问题。

NameError
undefined local variable or method `to_ary' for #<Mail::Part:0x0000000008e0c998>
Did you mean?  to_addrs

错误完全是随机出现的,其行为与https://yehudakatz.com/2010/01/02/the-craziest-fing-bug-ive-ever-seen/完全相同

我想做的是用猴子修补missing_method使其起作用。 所以我创建了一些测试,包括

let(:part) { Mail::Part.new }

it 'returns self' do
   allow_any_instance_of(Mail::Message).to receive(:method_missing).and_raise(NameError, 'error part')
   expect([part].flatten).to eq [part]
end

并创建了猴子补丁

require 'mail'

module Mail
  class Part < Message
    # monkey patched due to same behaviour like
    # https://yehudakatz.com/2010/01/02/the-craziest-fing-bug-ive-ever-seen/v
    def method_missing(name, *args, &block)
      begin
        super
        pp :hello
      rescue NameError => e
        return [self] if name.try(:to_sym) == :to_ary
        raise e
      end
    end
  end
end

该测试的目的是让Array#flatten对其内容调用to_aryMail::Part#method_missing通常没有定义,但是我创建了一个以处理NameError中可能的Mail::Message#method_missing并返回正确的值。

问题在于,调用了Mail::Part#method_missing,调用了super并引发了NameError,但是抢救没有任何作用。由于出现错误,pp :hello被跳过了。

所以测试以

结束
NameError: error part

  0) Mail::Part call flatten with NameError returns self
     Failure/Error: expect([part].flatten).to eq [part]

     NameError:
       error part
     # ./spec/lib/core_ext/mail/part_spec.rb:13:in `flatten'
     # ./spec/lib/core_ext/mail/part_spec.rb:13:in `block (4 levels) in <top (required)>'
     # ./spec/active_record_spec_helper.rb:19:in `block (2 levels) in <top (required)>'

另一个问题是,当我尝试时,测试最终以无限递归结束

def method_missing(name, *args, &block)
  return [self]
end

相同
def method_missing(name, *args, &block)
   begin
      raises_name_error
   rescue NameError => e
      return [self] if name.try(:to_sym) == :to_ary
      raise e
   end
end

def raises_name_error
   raise NameError, 'error part'
end

但是在这种情况下,救援块会处理NameError

有解决方案的想法吗?

1 个答案:

答案 0 :(得分:0)

解决者

module Mail
  class Part < Message
    def to_ary
      []
    end
  end
end

我最初的解决方案尝试不过分。