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

时间:2019-08-14 20:13:57

标签: ruby-on-rails devise ruby-on-rails-5

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

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

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

然后在我的自定义邮件程序中,我尝试访问@foo实例变量,但它仅返回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 additional data to devise mailer?How to pass instance variable to devise custom mailer in Rails?帖子。但是他们似乎都没有解决这个确切的问题。

1 个答案:

答案 0 :(得分:0)

首先让我解释一下,您有实例变量在ruby类中工作。

在ruby中,即使一个类(在您的情况下@foo)中的实例变量(在您的情况下RegistrationsController)也不会传递给其他类(在您的情况下CustomMailer),即使继承为ON。例如,请考虑:

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

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

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

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

如果希望这些变量传递给类,则应考虑使用以@@开头的类实例变量。例如:

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将自动传递到继承的类。


现在,将以上senario与您的问题相关。因此,您正在@foo中创建实例变量RegistrationsController,并且该变量不会传递给其他继承的类。 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