Omniauth && devise no route - ruby-on-rails

I trying to use omniauth to do login with social networks.
I using this wiki but i have no success
There is my code:
Routes.rb
get '/auth/:provider/callback', to: 'auth#create'
my auth controller:
class AuthController < ApplicationController
def create
p request.env['omniauth.auth']
end
def vkontakte
end
def facebook
end
end
Why i have route error?
No route matches [GET] "/auth/vkontakte"
Thnks

First, I think you have to do some config in your config/initializers/devise.rb.
config.omniauth :vkontakte, APP_ID, APP_SECRET
The you need to add something like
devise_for :users, controllers: { omniauth_callbacks: "omniauth_callbacks" }
with that you can implement the method in the
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def vkontakte
# you can do anything you want to do here. Note that you have access to the `request.env["omniauth.auth"]` which holds all the user information you'd require.
end
end
One more thing: if you check the devise documentation, you'd find different configuration options, but always be careful not to overwrite/create AuthController because by default that's what Omniauth uses, I think and I believe in order to work with devise, you should be inheriting some stuff from Devise not ApplicationController.

Related

Prevent multiple sessions accros model in devise

I'm on rails 6.0.3 and devise 4.7.3
I have 2 devise models in my rails application. User and Producer
On localhost:3000/users/sign_in, I can create a session with an user.
On localhost:3000/producers/sign_in, I can create a session with an producer.
I was suprised to have two parallels sesssions.
In the situtation, I have acces in the same time to a current_user and a current_producer
I want to prevent this, and if you sign in with a model, it sign out automatically with the other model.
Thanks for advices.
Finaly I found.
I overwrite the user controller.
# app/controllers/users/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController
def create
super
sign_out :producer
end
end
dont forget to config routes.rbto use this controller:
# config/routes.rb
Rails.application.routes.draw do
# ...
devise_for :users, controllers: {
sessions: 'users/sessions'
}
# ...
end
I did the same thing for producer.

Devise: Redirect to different path on failed user authentication

I am struggling to find a way to customize authenticate_user! so that instead of redirecting to the login page, it will redirect to a beta signup page if a user is not logged in.
Is there a way I can change the redirect path to a beta signup page conditionally by adding something like the below to the authenticate_user! method?
ENV['BETA_MODE'] ? redirect_to beta_signup_path : redirect_to login_path
You need to add custom devise controller to your app. You can do it as follow;
In config/routes.rb file;
devise_for :users, controllers: { registrations: "registrations" }
Add following controller content to app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
ENV['BETA_MODE'] ? beta_signup_path : login_path
end
end
More: https://github.com/plataformatec/devise/wiki/how-to:-redirect-to-a-specific-page-on-successful-sign-up-(registration)
I found a fix for this first mentioned here https://groups.google.com/forum/#!topic/plataformatec-devise/qymDM9u9n6Y.
I defined a custom authentication failure class in config/initializers/devise.rb like so:
config.warden do |manager|
manager.failure_app = CustomAuthenticationFailure
end
After doing that I created a file called custom_authentication_failure.rb in /vendor. The contents of that file looked like this:
class CustomAuthenticationFailure < Devise::FailureApp
protected
def redirect_url
ENV['BETA_MODE'] ? beta_signup_path : new_user_session_path
end
end
I also needed to add this in config/application.rb, because it wasn't already there:
config.autoload_paths += %W(#{config.root}/vendor)

Devise OmniAuth with a Multi-tenant Rails 5 App

Here is the situation. I have a multi-tenant rails app using the apartment gem where I need to implement a LinkedIn OmniAuth Strategy.
As you can see by my routes, Devise users, and the associated routes, are only persisted on the individual schemas of the subdomains.
Example Route:
Good: https://frank.example.io/users/sign_in
Bad: https://example.io/users/sign_in
Routes
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
...
devise_for :users, controllers: {
omniauth_callbacks: 'omniauth_callbacks'
}
devise_scope :user do
get '/users/:id', to: 'users/registrations#show', as: "show_user"
end
...
end
end
My specific problem is that LinkedIn does not support wildcards with their callback URLs so I am lost on how I might be able to direct users to the right domain after OAuth authentication.
So it turns out the answer was to pass parameters in the authorization link which would eventually get passed to the callback action throught request.env["omniauth.params"]
Authorization Link format:
Here I was having trouble adding the parameters to the Devise URL builder so I just manually added the parameters. This can probably be moved to a url helper
<%= link_to "Connect your Linkedin", "#{omniauth_authorize_path(:user, :linkedin)}?subdomain=#{request.subdomain}" %>
Routes:
Then I defined a route constrained by a blank subdomain pointing to the callback action.
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
...
devise_for :users, controllers: {
omniauth_callbacks: 'omniauth_callbacks'
}
resources :users
...
end
constraints(SubdomainBlank) do
root 'welcome#index'
...
devise_scope :user do
get 'linkedin/auth/callback', to: 'omniauth_callbacks#linkedin'
end
...
end
end
Controller:
I used this tutorial to set up my callback controllers: Rails 4 OmniAuth using Devise with Twitter, Facebook and Linkedin. My main objective with the callback controller was to have it reside in in the blank subdomain so I only had to give one call back URL to my LinkedIn Dev App. With this controller I search the omniauth params for the subdomain parameter and use that to switch to the proper schema.
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
raise ArgumentError, "you need a subdomain parameter with this route" if request.env["omniauth.params"].empty?
subdomain = request.env["omniauth.params"]["subdomain"]
Apartment::Tenant.switch!(subdomain)
...
end
}
end
could you register each domain as a callback with linked (I guess if you have a lot that becomes unmanageable quickly).. You could cookie the user before sending them to linkedin so when they return you know which subdomain they belong to.

Rails Devise Confirmable - redirect

The Rails docs for devise say that the instructions for how to redirect are incorrect:
https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users#redirecting-user
Does anyone know how to do this?
you will need to override devise confirmation controller.
in your routes.rb add this line
devise_for :users, controllers: { confirmations: 'confirmations' }
create file in and paste this code
class ConfirmationsController < Devise::ConfirmationsController
private
def after_confirmation_path_for(resource_name, resource)
your_new_after_confirmation_path #your path where you want to land
end
end
you may also need to restart the server.
Source : https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users#redirecting-user

Ruby on Rails Devise code after login

I have an RoR app using Devise for logins. There is some code that is executed when a new User record is created, by being put in the user.rb file as an after_create call/macro/whatever. I need to make this code run after each login, instead of running on new user creation.
With some Googling, it seems that one option is to place Warden callbacks in the devise.rb code. My questions are:
Is this right, and/or is there a better way to do this?
If this is the right approach ...
Should the Warden::Manager... method defs go in devise.rb inside of Devise.setup, or after it?
Is after_authentication the callback I should use? I'm just checking to see if a directory based on the user's name exists, and if not, creating it.
Just subclass Devise's sessions controller and put your custom behaviour there:
# config/routes.rb
devise_for :users, :controllers => { :sessions => "custom_sessions" }
And then create your controller like this:
# app/controllers/custom_sessions_controller.rb
class CustomSessionsController < Devise::SessionsController
## for rails 5+, use before_action, after_action
before_filter :before_login, :only => :create
after_filter :after_login, :only => :create
def before_login
end
def after_login
end
end
I found that using the Devise Warden hook cleanly allowed after login event trapping by looking for the ":set_user" :event.
In user.rb:
class User < ApplicationRecord
Warden::Manager.after_set_user do |user, auth, opts|
if (opts[:scope] == :user && opts[:event] == :set_user)
# < Do your after login work here >
end
end
end
I think this is an duplicate question. Yes you can execute code after every successful log in. you could write the code in your ApplicationController. Also have a look at 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)
Your Code Here
end
Reference Can I execute custom actions after successful sign in with Devise?
You could also inherit from devise session's class and use after_filter for logins.
UPDATED 2022
Warden now has built-in callbacks for executing your own code on after_authentication:
Warden::Manager.after_authentication do |user, _auth, _opts|
TelegramService.send("#{account.name} just logged in")
end
Source: https://github.com/wardencommunity/warden/wiki/Callbacks#after_authentication

Resources