在Rails应用程序中集成mailkick和ahoy_email会导致SystemStackError

时间:2016-05-10 20:44:26

标签: ruby-on-rails

我有一个rails应用程序,我们也在添加邮件列表功能。我试图整合两个宝石,ahoy_email(0.3.0)和mailkick(0.1.4),并遇到SystemStackError: stack level too deep错误。

邮件代码很简单:

class AdminMailer < ApplicationMailer
  # ...
  def generated_recommendations(recommendations)                                               
    @recommendations = recommendations
        mail(subject: "Recommendations generated for #{Date.today.strftime("%Y-%m-%d")}")      
  end 
end

在崩溃之前,堆栈跟踪如下所示:

--> #0  Mailkick::Mailer.mail(headers#Hash, &block#NilClass) at /home/mike/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/mailkick-0.1.4/lib/mailkick/mailer.rb:4
#1  AhoyEmail::Mailer.mail_with_ahoy(headers#Hash, &block#NilClass) at /home/mike/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/ahoy_email-0.3.0/lib/ahoy_email/mailer.rb:27
#2  Mailkick::Mailer.mail(headers#Hash, &block#NilClass) at /home/mike/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/mailkick-0.1.4/lib/mailkick/mailer.rb:4
#3  AhoyEmail::Mailer.mail_with_ahoy(headers#Hash, &block#NilClass) at /home/mike/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/ahoy_email-0.3.0/lib/ahoy_email/mailer.rb:27
#4  Mailkick::Mailer.mail(headers#Hash, &block#NilClass) at      /home/mike/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/mailkick-0.1.4/lib/mailkick/mailer.rb:4

看起来每个gem在另一个中调用mail方法(或者由于alias_method_chain调用而在AhoyEmail中调用mail_with_ahoy,见下文)。我用byebug和相关的Mailkick代码跟踪它(见***行)

module Mailkick                                                                                
  module Mailer                                                                                
    def mail(headers = {}, &block)                                                             
      message = super  # *** This ends up calling AhoyEmail::Mailer.mail_with_ahoy

      Mailkick::Processor.new(message).process

      message
    end
  end
end

和相关的AhoyEmail代码是(见***)

module AhoyEmail                                                                               
  module Mailer
    def self.included(base)
      base.extend ClassMethods                                                                 
      base.class_eval do
        # ...
        alias_method_chain :mail, :ahoy                                                        
      end                                                                                      
    end                                                                                        

    module ClassMethods                                                                        
    # ...
    def mail_with_ahoy(headers = {}, &block)
      # this mimics what original method does                                                  
      return message if @_mail_was_called && headers.blank? && !block

      message = mail_without_ahoy(headers, &block)  # *** This calls Mailkick::Mailer.mail
      AhoyEmail::Processor.new(message, self).process                                          
      message
    end     
  end     
end

两个宝石的功能略有不同,在AhoyEmail的情况下是通过:

ActionMailer::Base.send :include, AhoyEmail::Mailer

在Mailkick的案例中,它是通过:

ActionMailer::Base.send(:prepend, Mailkick::Mailer)

对我来说,看起来宝石只是冲突(因为他们都在改变ActionMailer::Base.mail并不能很好地发挥作用)并且我没有看到明显的解决方法。自从Mailkick在Ahoy电子邮件的自述文件中被引用后,我感到很惊讶,所以我想我可能会遗漏一些明显的东西。任何帮助非常感谢!

1 个答案:

答案 0 :(得分:0)

事实证明我使用的ahoy_email gem(来自RubyGems)的版本已经在github上更新以解决此问题。解决方案是将Gemfile中的相应行更新为:

gem 'ahoy_email', github: 'ankane/ahoy_email'

请参阅github上的相关问题: https://github.com/ankane/ahoy_email/issues/61

解析此问题的ahoy_email gem中的差异在于: https://github.com/ankane/ahoy_email/commit/9416ab989b942cd556d09380f9072c260c2d6551

alias_method_chain的使用已经消失,取而代之的是Module#prepend,它解决了问题。仔细观察一下,我发现在Rails 5中将弃用alias_method_chain(请参阅https://github.com/rails/rails/pull/19434)。

编辑2016-05-12:此修补程序发布了新版本(0.3.1)的gem,所以现在我已将我的Gemfile更新为: gem 'ahoy_email', '>= 0.3.1'