I use Devise for authentication in my Rails app.
In my registrations_controller
I set an instance variable like this:
class RegistrationsController < Devise::RegistrationsController
def create
@foo = "bar"
super
end
end
In my customized mailer I then try to access the @foo
instance variable, but it just 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
Anyone who could help?
I have looked through the posts 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?. But none of them seem to deal with this exact problem.
First let me explain you have instance variables work in ruby classes.
In ruby, instance variable(in your case @foo
) in a class(in your case RegistrationsController
) do not pass down to other classes(in your case CustomMailer
) even if inheritance is ON. For Example consider:
class Abc
@first = "First"
puts "Abc: #{@first}"
end
class Def < Abc
puts "Def: #{@first}"
end
# => Abc: First instance variable
# => Def:
As you can see the class Def
cannot have access to @first
instance variable. Thus, instance variables don't get passed down to other classes automatically.
If you want these variables to pass down the class, you should consider using Class Instance Variables which starts with @@
. Ex:
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
Now @@first
will pass down to inherited class automatically.
Now, relate the above senario to your question. So you're creating a instance variable @foo
in RegistrationsController
and it will not be passed to other inherited classes. Under the hood both Devise::RegistrationsController
and DeviseMailer
are inherited from Devise.parent_controller
.
So, better way to work with it is to send the @foo
as a parameter, for example:
class RegistrationsController < Devise::RegistrationsController
def create
@foo = "bar"
CustomMailer.confirmation_instructions(user, token, opts={foo: @foo})
...
end
end
Then you can access this in your CustomMailer:
def confirmation_instructions(record, token, opts={})
puts opts[:foo]
super
end