Can I execute custom actions after successful sign in with Devise? - ruby

I have an app that has basic Devise authentication. After sign in, I would like to look up the user account (user belongs_to account, account has_many users), and store that in the session so that it is available like the #current_user.
What is the rails way of storing session in formation like this?
Is there a hook I can use with Devise to execute code after successful sign-in?

Actually, the accepted answer does not work properly in case of combined Omniauth and Database login modules in Devise.
The native hook that is executed after every successfull sign in action in Devise (disregarding the user authentication channel) is warden.set_user (called by devise sign_in helper: http://www.rubydoc.info/github/plataformatec/devise/Devise/Controllers/SignInOut#sign_in-instance_method).
In order to execute custom action after successfull user sign in (according to Warden Docs: https://github.com/hassox/warden/wiki/Callbacks), put this into initializer (eg. after_sign_in.rb in config/initializers)
Warden::Manager.after_set_user except: :fetch do |user, auth, opts|
#your custom code
end
Update 2015-04-30: Thanks to #seanlinsley suggestion (see comments below), I have corrected the answer to include except: :fetch in order to trigger the callback only when user is authenticated and not every time it is set.
Update 2018-12-27 Thanks to #thesecretmaster for pointing out that Warden now has built-in callbacks for executing your own code on after_authentication https://github.com/wardencommunity/warden/wiki/Callbacks#after_authentication

Edit: Please consider that this was once a good solution, but there are probably better ways of handling this. I am only leaving it here to give people another option and to preserve history, please do not downvote.
Yes, you can do this. The first resource I'd look at is http://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in. Also, check out How to redirect to a specific page on successful sign up using rails devise gem? for some ideas.
You can do something like:
def after_sign_in_path_for(resource_or_scope)
session[:my_account] = current_user.account
profile_url
end
You can implement this method in your ApplicationController or in a custom RegistrationsController.

i'm using rails 5 and devise 4.2.1, my solution is overide devise function on user model:
def after_database_authentication
# here's the custom code
end
and the user model will look like this:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:timeoutable, :lockable
def after_database_authentication
# here's the custom code
end
end
it was called just after the authentication,
i read it from this devise documentation, hope this could help

I resolved this problem by overriding the create method of the session controller like following
class Admin::SessionsController < Devise::SessionsController
def create
super
# here goes my code
# my settings, etc
# do something with current_admin.fullname, for example
end
end
In other words, if authentication is successful (by calling super) then I perform my settings.

In application controller, you can simply add an after action.
app/controllers/users/application_controller.rb
class ApplicationController < ActionController::Base
after_action :do_something
def do_something
# do something
end
end

Related

Welcome emails in Ruby

I'm using Ruby and Devise:Confirmable. A day or so after a new user has registered and confirmed a new trial account we'd like to automatically send him or her a 'follow up email'. Is this something we should also do through devise, or is there a separate gem or process we should implement?
Since you are using Devise already, you can just overwrite the confirmation controller, try something like this.
class ConfirmationsController < Devise::ConfirmationsController
# GET /resource/confirmation?confirmation_token=abcdef
def show
super do |resource|
YourMailerClass.follow_up(resource).deliver_later(wait_until: 1.day.from_now) if resource.errors.empty?
end
end
end
You also need to update the routes.rb file, add the option controllers: { confirmations: :confirmations } at the end of the line where you define devise_for (restart your server after this).
I'm assuming you already have a background jobs proccesor, like sidekiq
Hope it helps

ruby rails send an email after sign up with devise without confirmable

i create a sign in /up with devise for my app rails , and i would like just send a email of welcoming but without confirmable or redirecting,
"devise :confirmable, ...
has_many :emails
delegate :confirmation_sent_at, :confirmed_at, :confirmation_token, to: :primary_email
def primary_email
emails.primary || (emails.first if new_record?)
end"
i read the documentation of devise but i didn't find ( or understand) my answer.
thx for your help i am new in the community and don't speak english well.
You can set up an after_action in the model to send an email.
model
after_action :send_welcome_email, only: [:sign_up]
You will need to create the send_welcome_email yourself. Look up actionMailer which will give you an idea of what you need to do.

Rack middleware how to redirect to a view in my Rails application

In my Rails 3.1 app I created a Rack Middleware to verify access. If access is not approved user is to be redirected to a page. Specifically it will be a page I already have in my views. Suppose I am trying to redirect to dummy.html.erb with I have defined in my routes.rb as
match '/dummy', to :'page#dummy'
with page being my controller.
I've tried the following but I appear to be stuck in some redirect loop.
My Rack middleware located in /lib :
class AccessVerifier
def initialize(app)
#app = app
end
def call (env)
#....
#....do some type of verification here and redirect if fail verification
#....
[301, {"Location" => '/dummy', "Content-Type" => "text/html"}, []]
end
end
In application.rb I have
config.autoload_paths += %W(#{config.root}/lib)
config.middleware.use "AccessVerifier"
I also tried calling a controller in my middleware but again I am caught in some redirect loop. I called the controller from my middleware class like this:
def call (env)
...
status,headers,response=PageController.action("validateAccess").call(env)
end
and in my controller:
class PageController < ApplicationController
def validateAccess
redirect_to :controller => 'page', :action => "dummy"
end
...
end
I've seen redirecting done successfully without the use of Rack Middleware, for example only with controllers, but please note that I need to do this in middleware before my application is run.
The answer is so simple I felt silly. The problem is that when I redirect to somewhere say /dummy that in turns causes another pass through the Rack middleware and goes through my AccessVerifier code all over again which redirects to /dummy and does this over and over again thus causing the redirect loop. To fix it I force a stopping point by checking if the incoming path is included in the list of my stopping points(with /dummy being in that list) then stop. So an example in pseudo code
if path in ListOfAcceptableStoppingPoints
#app.call(env)
This fixes the redirect loop issue but now I am questioning if it would be better for my specific case to not use rake middleware as I have found that now I am filtering other things out such as assets. Sure I could try to go through and pick out everything I think I need to allow to go through but this seems too tedious and not correct. It seems like ultimately, I need to do my filtering at the rails level not at the rack level.
I don't have an answer off of the top of my head to directly answer your question. However, I would suggest using the cancan gem to handle authorization instead of creating a homegrown solution. See https://github.com/ryanb/cancan

How to allow access only to logged in users restricting direct entry of url?

in a Rubyonrails application i want only logged in users to enterinto the inner pages?
how can i redirect the direct entered urls to index page?
in php if(!isset($_SESSION[id]) { header("location:index.php") }, how this can be implemented in ruby on rails
here goes
In application_controller.rb:
Putting this code in application_controller will make it available to all your controllers.
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def confirm_logged_in
unless session[:id]
flash[:notice] = "Please log in"
redirect_to :root
return false
else
return true
end
end
end
Then you can make use of this method in any of the controllers that require it, for eg
If you need to confirm that users are logged in for the show action, then
class UsersController < ApplicationController
before_filter :confirm_logged_in, :only => [:show]
def show
#all your code
end
end
should work, as this will confirm that users accessing this show url have logged in.
For more info checkout this link to rails guides on filters. There could be more efficient ways of achieving this as well.
However, i would suggest using a gem like Cancan (Github) as i have used this in many apps and works well. The code presented above is basic and there are many better and advanced ways to handle this but it should do the job.Hope it helps.

Devise: Is it possible to NOT send a confirmation email in specific cases ? (even when confirmable is active)

Here is my situation, I use devise to allow users to create account on
my site and manage their authentication.
During the registration process I allow customers to change some
options, leading to an actually different account being created but
still based on the same core user resource.
I would like to choose not to send a confirmation email for some of
those account types. I don't care if the account do not get confirmed
and user cannot log in, that's ok, no pb with that.
How would I go about doing that ?
Thanks,
Alex
Actually it's quite easy once I dig a little deeper.
Just override one method in your User model (or whatever you are using):
# Callback to overwrite if confirmation is required or not.
def confirmation_required?
!confirmed?
end
Put your conditions and job's done !
Alex
If you just want to skip sending the email but not doing confirmation, use:
# Skips sending the confirmation/reconfirmation notification email after_create/after_update. Unlike
# #skip_confirmation!, record still requires confirmation.
#user.skip_confirmation_notification!
If you don't want to call this in your model with a callback overwrite this method:
def send_confirmation_notification?
false
end
You can also simply add the following line of code in your controller before creating the new user:
#user.skip_confirmation!
I don't know if Devise added this after the other answers were submitted, but the code for this is right there in confirmable.rb:
# If you don't want confirmation to be sent on create, neither a code
# to be generated, call skip_confirmation!
def skip_confirmation!
self.confirmed_at = Time.now
end
I was able to do something similar with the functions:
registrations_controller.rb
def build_resource(*args)
super
if session[:omniauth] # TODO -- what about the case where they have a session, but are not logged in?
#user.apply_omniauth(session[:omniauth])
#user.mark_as_confirmed # we don't need to confirm the account if they are using external authentication
# #user.valid?
end
end
And then in my user model:
user.rb
def mark_as_confirmed
self.confirmation_token = nil
self.confirmed_at = Time.now
end

Resources