将实例变量从 Devise 控制器传递到自定义邮件程序?

Pass instance variable from Devise controller to custom mailer?

我在 Rails 应用程序中使用 Devise 进行身份验证。

在我的 registrations_controller 中,我设置了一个这样的实例变量:

class RegistrationsController < Devise::RegistrationsController
  def create
    @foo = "bar"
    super
  end
end

然后在我的自定义邮件程序中,我尝试访问 @foo 实例变量,但它只是 returns nil:

class CustomMailer < Devise::Mailer
  helper :application
  include Devise::Controllers::UrlHelpers

  def confirmation_instructions(record, token, opts={})
    Rails.logger.error @foo.inspect # => nil
    super
  end
end

有人可以帮忙吗?

我已经浏览了帖子 How do I add instance variables to Devise email templates?, , How to pass instance variable to devise custom mailer in Rails?。但是 none 似乎可以解决这个问题。

首先让我解释一下你有实例变量在 ruby classes.

中工作

在ruby中,class(在你的情况下RegistrationsController)中的实例变量(在你的情况下@foo)不要传递给其他classes(在你的情况下 CustomMailer) 即使继承是开的。例如考虑:

class Abc
  @first = "First"
  puts "Abc: #{@first}"
end

class Def < Abc
  puts "Def: #{@first}"
end

# => Abc: First instance variable
# => Def:

如您所见,class Def 无法访问 @first 实例变量。因此,实例变量不会自动传递给其他 classes。

如果你想让这些变量传递给class,你应该考虑使用Class以@@开头的实例变量。例如:

class Abc
  @@first = "First instance variable"
  puts "Abc: #{@@first}"
end

class Def < Abc
  puts "Def: #{@@first}"
end

# => Abc: First instance variable
# => Def: First instance variable

现在 @@first 将自动继承 class。


现在,将上述情景与您的问题联系起来。所以你在 RegistrationsController 中创建了一个实例变量 @foo 并且它不会被传递给其他继承的 classes。 Devise::RegistrationsControllerDeviseMailer 都继承自 Devise.parent_controller.

因此,使用它的更好方法是将 @foo 作为参数发送,例如:

class RegistrationsController < Devise::RegistrationsController
  def create
    @foo = "bar"
    CustomMailer.confirmation_instructions(user, token, opts={foo: @foo})
    ...
  end
end

然后您可以在您的 CustomMailer 中访问它:

def confirmation_instructions(record, token, opts={})
  puts opts[:foo]
  super
end