Rails 4.1: access current_user in ActionMailer::Preview - ruby-on-rails

Rails 4.1 has a nice way to preview mailers with ActionMailer::Preview. All of my mailers take a user parameter, and I would like to pass in current_user (from Devise) for the preview.
If I try this, it doesn't work.
class SubscriptionsMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/subscriptions_mailer/new
def new
SubscriptionsMailer.new(current_user)
end
end
It returns undefined local variable or method 'current_user' for #<SubscriptionsMailerPreview:0xa6d4ee4>.
I suspect this is because current_user is defined by Devise in ApplicationController, and according to the docs, ActionMailer uses AbstractController::Base. In that case, would storing current_user in a class variable be a bad idea?
Does anyone know how I can use the current_user helper in ActionMailer::Preview?

What would happen if you move your mailer job to the background? How would you get the current user then?
The mailer and its preview should not know about the current_user. The mailer's job is to send the mail to a user it receives. The preview is there to visually demonstrate its behaviour.
Create a new user in your mailer preview, and pass it to the mailer.
def new
user = User.create! # etc...
SubscriptionsMailer.new(user)
end
It doesn't matter who the user is. It matters that it's a user object.
If you want to test that the application will send a mail to the current_user, write a functional test for that.

You are right method defined in Controller won't be available in helper.
These posts can help you:
Where do I put helper methods for ActionMailer views? Access helpers from mailer?
https://www.ruby-forum.com/topic/168949

Related

How to I create a preview for devise_intiable mailer?

I hooked up devise_invitable gem
And everything is working correctly in my dev environment. I can view the mailer html in the terminal, I can copy the URL with the token it sends. And when I put that in browser and go to that path it works perfectly.
I would however like to create a preview for this so I can preview the mailer as I get that part how I want it.
Here's what I've tried so far.
In test/mailers/previews
and my code is something like this:
class InviteAdminPreview < ActionMailer::Preview
def invite
InviteAdminMailer.invite(Admin.last)
end
end
but this isn't really working because I don't know what the actual invite mailer is called. Because in app/mailers where I would have expected devise_invitable to place this mailer, there is nothing there.
So should I create my own mailer here called InviteAdminMailer? Or is there some other way to do it?
Also will i have to create this .invite method myself in this mailer so this preview will work?
First of all, to create a customized mail for devise_invitable usage, you can reference the article "Customizing for different Invite use cases (emails etc.)" https://github.com/scambra/devise_invitable/wiki/Customizing-for-different-Invite-use-cases-(emails-etc.) from devise_invitable wiki.
According to devise_invitable source code ( https://github.com/scambra/devise_invitable/blob/cf77519ca9d02c112d99fd176a8852272c1b8d99/lib/devise_invitable/models.rb#L210 ), it uses the mailer provided by devise, so there is no devise_inviatble mailer. If you want to preview devise mails, you can do something as below:
From: https://gist.github.com/ThawanFidelis/ac4a215b841619eae7d8
# config/enviroments/development.rb
config.action_mailer.preview_path = "#{Rails.root}/app/mailer_previews"
# app/mailer_previews/devise_mailer_preview.rb
class Devise::MailerPreview < ActionMailer::Preview
def confirmation_instructions
Devise::Mailer.confirmation_instructions(User.first, {})
end
def unlock_instructions
Devise::Mailer.unlock_instructions(User.first, "faketoken")
end
def reset_password_instructions
Devise::Mailer.reset_password_instructions(User.first, "faketoken")
end
end
This worked for me
def invitation_instructions
Devise::Mailer.invitation_instructions(User.all.sample, 'faketoken')
end

Call helper function from rails 4 notifications subscribe

I need to save all controller notification to database. I create a /config/initializers/notifications.rb
ActiveSupport::Notifications.subscribe('process_action.action_controller') do |name, start, finish, id, payload|
Action.create(
action_type: name,
user: current_user,
data: payload
)
end
but I get error:
undefined local variable or method `current_user' for main:Object
current_user is a helper it app/helpers/session_helper.rb and it works in entire application.
I need to know user, which made action. How can I call current_user in this context?
current_user is usually set in the application_controller of your
application. If you use a gem like Devise to handle user
authentications for example, they take care of setting such method for
you.
The initializers' code is executed when you launch your application on
your server (local machine or remote server), therefor you understand
that a "current_user" (understand a "logged in" user) simply does not
exists (yet).
Source - is it possible for current_user to be initializer, in rails 3?
Hope this helps!
current_user is a helper it app/helpers/session_helper.rb and it works in entire application.
Let me correct you here.
You can't access current_user in your initializer files. Initializers are run once on application startup, so don't expect accessing current_user like this.
I found solution: append_info_to_payload
class ApplicationController < ActionController::Base
...
def append_info_to_payload(payload)
super
payload[:current_user] = current_user
end
From this answer:
How to add attribute to existing Notifications payload?

Rails/devise current_user accessed in model but it's nil

I needed to access the current_user in my another model. I googled and found a few solutions and tried this.
But just one difference: I didn't set the User.current_user in the controller. WHY?
Like in the answer I followed I'm not adding data to my second model from views but by rendering data via a url (with open-uri, it's csv data I'm fetching).
So in my second model I do:
Person.create(username: User.current_user.username)
It gives:
NoMethodError: undefined method `username' for nil:NilClass
which isn't working (which is obvious I guess). In console when I do User.current_user it shows:
1.9.3p448 :002 > User.current_user
=> nil
I think why it isn't working is because I'm accessing the User.current_user directly from model and model cannot get the current_user unless it is given that. (right?)
But this would definitely work if I access it via a login page and set the User.current_user in the controller.
But as I'm directly fetching the data from url, I'm directly making new entries for my Person model in model itself.
So how do I set the User.current_user?
Is there any workaround for this? Edit's for the question's title are required.
current_user is available by default as a helper method within Devise. From the documentation:
# For the current signed-in user, this helper is available:
current_user
The current_user isn't accessed directly via the model, per se, but rather, though the Devise module, which looks up the User object that is logged into the current session, and then returns to current_user.
Thus, the current user isn't accessed via User.current_user (there is no current_user method on User, as the error message is saying). You access it purely by invoking the current_user helper method within a controller or view.
UPDATE:
You're well advised to keep your controller and model layers separate. One way of doing what you've proposed is to create a class function on the Person model wherein you explicitly pass the username of your User object from within your controller:
# in your controller
Person.create_with_username(:username => current_user.username)
# app/models/person.rb
def self.create_with_username(username)
self.create(username)
end

Rails devise user function

How do I execute a particular function after a user has signed up.
(I wanted to add to one of my associations, I already have it coded in a non-devise rails but now I need it here)
Device has provided helper action 'after_sign_in_path_for' you can override it within your application controller.
def after_sign_in_path_for(resource_or_scope)
.... #write your customize code or call any method
end
For sign up it would look like:
def after_sign_up_path_for(resource_or_scope)
if resource_or_scope.is_a? User # and perhaps other conditions
#... do something, go somewhere
else
super
end
end
Ofc. Assuming that your Devise user model is called User.
You can use the after_create callback in your User model.
The following guide has tons of examples: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

How do I run a check on a user's account every time they login using Devise in Rails 3?

I am using Devise, and when someone logs in I would like to execute a custom method.
Similarly to how you use before_save to execute a method before the account/model is updated/saved, or before_create to do the same before the object is initially created.
I would like to do the same, but for users logging in.
How do I do that ?
In your application_controller.rb add the following code:
def after_sign_in_path_for(resource)
execute_custom_function()
super
end
You can utilize Devise's Controller Helper.

Resources