rails 3:如何在动作邮件中中止交付方式?

时间:2011-07-01 16:44:52

标签: ruby-on-rails actionmailer

在我的邮件控制器中,在某些情况下(缺少数据),我们会中止发送电子邮件。

在这种情况下如何在不渲染视图的情况下退出控制器方法?

  

返回@ some_email_data.nil?

由于视图仍然呈现,所以没有做到这一点(每次尝试使用@some_email_data都会抛出错误,除非我添加了大量的nil检查)

即使我做了零检查,它也会抱怨没有“发送者”(因为在我设置发件人和主题的行之前,我应该先做'返回'。

render ... return

也不是

基本上,RETURN不会在邮件程序中返回!

6 个答案:

答案 0 :(得分:26)

比接受的答案更简单的解决方案是:

class SomeMailer < ActionMailer::Base
  def some_method
    if @some_email_data.nil?
      self.message.perform_deliveries = false
    else
      mail(...)  
    end  
  end
end

如果您正在使用Rails 3.2.9(或更晚的事情) - 那么您最终可以有条件地呼叫mail()。这是相关的GitHub thread。现在代码可以像这样重做:

class SomeMailer < ActionMailer::Base
  def some_method
    unless @some_email_data.nil?
      mail(...)  
    end  
  end
end

答案 1 :(得分:18)

我刚刚遇到同样的事情。

我的解决方案如下:

module BulletproofMailer
  class BlackholeMailMessage < Mail::Message
    def self.deliver
      false
    end
  end

  class AbortDeliveryError < StandardError
  end

  class Base < ActionMailer::Base

    def abort_delivery
      raise AbortDeliveryError
    end

    def process(*args)
      begin
        super *args
      rescue AbortDeliveryError
        self.message = BulletproofMailer::BlackholeMailMessage
      end
    end
  end
end

使用这些包装邮件将如下所示:

class EventMailer < BulletproofMailer::Base
  include Resque::Mailer
  def event_created(event_id)
    begin
      @event = CalendarEvent.find(event_id)
    rescue ActiveRecord::RecordNotFound
      abort_delivery
    end
  end
end

我的博客中也是posted

答案 2 :(得分:2)

我发现此方法似乎是侵入性最小的方法,因为它适用于所有邮件方法,而无需您记住捕获错误。在我们的情况下,我们只希望针对某些环境完全禁用邮件程序的设置。在Rails 6中进行了测试,尽管我确信它也可以在Rails 5中正常工作,甚至可能更低。

class ApplicationMailer < ActionMailer::Base
  class AbortDeliveryError < StandardError; end

  before_action :ensure_notifications_enabled
  rescue_from AbortDeliveryError, with: -> {}

  def ensure_notifications_enabled
    raise AbortDeliveryError.new unless <your_condition>
  end

  ...

end

空的lambda导致Rails 6仅返回一个ActionMailer::Base::NullMail实例,该实例不会被传递(就像您的邮递员方法没有调用mail或过早返回一样)。

答案 3 :(得分:0)

设置self.message.perform_deliveries = false对我不起作用。

我使用了与其他一些答案类似的方法-使用错误处理来控制流量并阻止邮件的发送。

下面的示例正在中止邮件从非生产ENV发送到未列入白名单的电子邮件,但是辅助方法逻辑可以满足您的方案需要。

class BaseMailer < ActionMailer::Base
  class AbortedMailer < StandardError; end

  def mail(**args)
    whitelist_mail_delivery(args[:to])
    super(args)
  rescue AbortedMailer
    Rails.logger.info "Mail aborted! We do not send emails to external email accounts outside of Production ENV"
  end

  private

  def whitelist_mail_delivery(to_email)
    return if Rails.env.production?

    raise AbortedMailer.new unless internal_email?(to_email)
  end

  def internal_email?(to_email)
    to_email.include?('@widgetbusiness.com')
  end
end

答案 4 :(得分:-2)

我只是清除@to字段并返回,所以当它没有任何东西时提供中止。 (或者在设置@to之前返回)。

答案 5 :(得分:-4)

我没有花费很多时间使用rails 3,但你可以尝试使用

redirect_to some_other_route

或者,如果你真的只是检查缺失的数据,你可以对表单字段进行js验证,只有在通过时才提交。