Performing model method in after_sign_up_path_for(resource) - ruby-on-rails

I am trying to send an welcome email in a rails application after a user signs up. Currently I have a redirection that will take them to a specific page. I have a mailer method that I want to send but it doesn't work. Is there another way to do this?
def after_sign_up_path_for(resource)
if current_user
ModelMailer.new_user_notification(#user).deliver
'/dashboard'
end
end

You could send the email in the user model, with a simple after_create:
class User << ActiveRecord::Base
# ...
after_create: send_welcome_email
def send_welcome_email
ModelMailer.new_user_notification(self).deliver
end
end

Related

How to access current user in a mailer file before action

I have a before action in a user mailer file, which is supposed to stop mailers sending if a column on user is set to true or false. However current user is currently unavailable. I understand why, but was wondering if there was a way to do this.
I want to avoid adding the check_if_users_can_receive_mailers at the top of each mailer method.
before_action :check_if_users_can_receive_mailers
#methods that send mailers
private
def check_if_users_can_receive_mailers
current_user.send_mailers?
end
You have to make the current user available as a attribute or class variable. The most straight forward method is something like this:
class MailerBase < ActionMailer::Base
before_action :check_if_users_can_receive_mailers
attr_accessor :user
def initialize(user)
#user = user
end
private
def check_if_users_can_receive_mailers
user.send_mailers?
end
end
class SomeMailerClass < MailerBase
end
In Rails only your controller and views are request aware. Mailers and models and other classes in your application are not and they cannot get the current user since they can't access the session nor the method current_user which is a helper method mixed into your controller (and the view context).
If your mailers need to know about the current user the most logical approach is to pass that information into the mailer:
class UserMailer < ApplicationMailer
def intialize(user)
#user = user
end
end
However a mailer should only have one job - to send emails and it shouldn't be questioning if it should do the job or not. Determining if you should send an email to the user should be done elsewhere. You can place this logic in the controller or even better in a service object:
# app/notifiers/user_notifier.rb
class UserNotifier
def initialize(user, event:)
#user = user
#event = event
end
def notify
if #user.wants_email?
spam_user!
end
send_in_app_notification
end
def self.notify(user, event:)
new(user, event:)
end
private
def spam_user!
# ...
end
def send_in_app_notification
# ...
end
end
class ThingsController
def create
#thing = Thing.new
if #thing.save
UserNotifier.notify(current_user, event: :thing_created)
redirect_to #thing
else
render :new
end
end
end

Rails devise redirect after confirming email

I want to redirect to the rooth path after a users confirms his email by clicking on the activation link. The devise wiki says to implement the following method in the registrations controller:
def after_inactive_sign_up_path_for(resource_or_scope)
session["user_return_to"] || root_path
end
But it doesnt get picked up and keeps directing my to the following url:
http://localhost:3000/users/sign_in
How can i override this behaviour of devise?
def after_inactive_sign_up_path_for(resource_or_scope)
root_path
end
Anonymousxxx posted the answer in a comment. The method is supposed to be in the confirmationscontroller.
module Users
class ConfirmationsController < Devise::ConfirmationsController
protected
def after_confirmation_path_for(_, _)
root_path
end
end
end

devise: is it possible to sign in user in the model?

My app creates a user in a callback of a model and I can't figure out how to seamlessly sign him in after that, as sign_in helper is available only in the controller.
after_validation do
return unless errors.empty?
if create_account == "1"
begin
self.user ||= User.create!(...)
rescue => e
errors.add(:create_account, 'bla bla')
end
end
end
So how to sign in user after it has been created (in the model)?
You can not sign in a user through the model and you don't want to do that either.
Why are you using a validation callback here?
If you move part of this logic to your controller you can easily achieve what you want.
def MyController < ApplicationController
def my_action
my_instance.user ||= User.new(...)
if my_instance.user.save
sign_in my_instance.user
end
end
end

devise overrule devise SessionController broke login

I have extended the devise controller for sessions. To add some extra functionality when a user logs in. Now upon login, IF no username or password are entered I get error :
SessionsController#create
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
I searched last week for up to 2 hours how to fix this anyone can help me out on this one? Would be highly appreciated
How to correctly add my custom functionality but still preserve the Devise create action?
class SessionsController < Devise::SessionsController
def create
#user = User.where(:id => current_user.id).first
#moderated = Asset.where(:attachable_id => current_user.id, :moderated => true).first
if #user.sign_in_count.to_i == 1
def after_sign_in_path_for(resource)
"/welcome/basics"
end
else
if #moderated.nil?
unless #user.has_photo?
def after_sign_in_path_for(resource)
"/home/no_photo"
end
end
else
def after_sign_in_path_for(resource)
"/home/moderated"
end
end
end
end
end
If your additional functionality consists of redirecting the user to a different page at his first login i would suggest defining after_sign_in_path_for in the application controller as suggested by the wiki.
class ApplicationController < ActionController::Base
private
def after_sign_in_path_for(resource)
if current_user.sign_in_count == 1
"/welcome/basics"
else
"/other/path"
end
end
end
Please note that this only works if User is the only resource that can sign into your application. Otherwise you would have to differentiate in this method as well via the resource parameter.

Whitelisting with devise

I am using devise to manage user authentication in my rails app. Devise is really great for that.
However I have a special requirement for my application: A user must be whitelisted before he can register as a User.
So there is a admin which creates a list of allowed emails. A user registers with a email and if the email is in the whitelist table he will be registered. If however, the mail is not in the whitelist, the registration should be aborted with a message like "You are not yet invited".
Do you have an idea how that could be solved with devise?
Thanks in advance.
I would just use model validation. I'm assuming your User class has the devise method
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable #etc
before_validation :whitelisted
def whitelisted
unless celebrityemail.include? email
errors.add :email, "#{email} is not on our invitation list"
end
end
end
What you can do is create your own registrations controller and extend the device one like:
class MyRegistrationController < Devise::RegistrationsController
def create
# do your checks
super
end
end
see: https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb
And: https://github.com/plataformatec/devise/wiki/How-to:-Customize-routes-to-user-registration-pages
Good luck!
I did create my own controller as suggested:
class Users::RegistrationsController < Devise::RegistrationsController
def create
email = params[:user][:email]
if Admin::Whitelist.find_by_email(email) != nil
super
else
build_resource
set_flash_message :error, "You are not permitted to sign up yet. If you have already payed your registration fee, try again later."
render_with_scope :new
end
end
end
I placed it in app/users/registrations_controller.rb. Then I had to copy the devise registration views into app/views/users/registrations because the default views were not used.
It is working now, thanks for your help

Resources