Devise + Omniauth + remember_me - devise

There seems to be some confusion on how to get remember me working with Omniauth.
According to this wiki, you need to have the following in your OmniauthCallbacksController:
remember_me(user)
On the other hand, according to this issue, you just need to do this:
user.remember_me = true
In addition, making remember_me default to true according to this, you just need to add the following to your User.rb
def remember_me
true
end
Not sure which one is the official answer, and all three doesn't work for me. It only works for Chrome on Mac, but doesn't for Firefox Mac & Chrome Windows. Not sure what is going on.
My code looks like this:
# -*- encoding : utf-8 -*-
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
include Devise::Controllers::Rememberable
def all
omniauth = request.env["omniauth.auth"]
auth = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if auth
auth.update_with_omniauth omniauth
auth.save!
# ???
remember_me auth.user
auth.user.remember_me = true
if user_signed_in?
redirect_back_or settings_path(current_user)
else
sign_in_and_redirect auth.user, event: :authentication
end
else
if user_signed_in?
current_user.build_auth(omniauth).save!
redirect_back_or settings_path(current_user)
else
session["devise.omniauth"] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
alias_method :facebook, :all
alias_method :twitter, :all
end

This was answered here by Jose Valim.
The first option is the correct one. The other two simply set the
default value of the field to true, which means it will be
automatically remembered whenever the first one is called.
If it works in some browsers or not, it is likely a browser issue
because the server is definitely sending the proper cookies. Try to
confirm if the cookie is indeed correct and find out if the browser is
storing it properly.

Related

find_by_* method is not returning the object

I am trying to set up a simple authentication for my rails application. I have a security_users scaffold and have created some users.
When, I am trying to log in using some of these accounts it seams that the "find_by_*" method is not able to detect the current one.
This is how my session controller looks like (I have comment the password check in purpose in order to debug the issue):
class SessionsController < ApplicationController
def new
end
def create
#security_user = SecurityUser.find_by_email(params[:email])
if #security_user #&& #security_user.authenticate(params[:password])
session[:security_user_id] = #security_user.id
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render 'new'
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end
So, when I try to create a session (to log in) I am redirect to the session 'new' template. This is the debug information:
which seems to be all right. Why the following statement could not find the record:
SecurityUser.find_by_email(params[:email])
EDIT:
When I entered the line above in the console it is returning the record:
First off, unless this is a simple exercise in Rails authentication, you should use Devise or AuthLogic at this stage.
Second, are you sure that params[:email] contains the email you are looking for? From your params, it looks to me like you want to use params[:session][:email].
Third, you should move this down into the model. For example:
class SecurityUser < ActiveRecord::Base
def self.authenticate(params)
user = where(email: params[:email]).first
(user && user.password == params[:password]) ? user : false
end
end
And in the controller:
#user = SecurityUser.authenticate params[:session]
session[:user_id] = user.id if #user
Note above that the password is not hashed - you should not save a plain text password - but that's not what this is about.
Also note that now you should use where().first instead of find_by.

Devise and Facebook Custom Routing

I am trying to create the user registration views and model on my website but I am having a small issue :
I am using devise and omniauth to get the facebook connect features working and it works,
But I want my facebook users when they sign in the first time to create their password,
That is also working, I redirect them to the filled sign up form and they only have to enter their password. But I want them to go to a second "sign_up form" named /views/registrations/new_facebook.html.erb where they can only enter their password and I will also add some other information,
I created the correct view and tested it but I have no idea how to create the correct routes to bypass Devise default
match '/facebook' => 'registrations#new', :as => 'new_facebook_user_registration'
I believe the issue is with match because that's what's not recognised,
If anyone can help me that would be great thanks,
I added my controller code for omniauth :
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash[:success] = "Welcome back"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_facebook_user_registration_url
end
end
alias_method :facebook, :all
end
How can I make the redirect_to new_facebook_user_registration_url actually work ?
devise_scope :user do
match "registrations/new_facebook" => "registrations#new_facebook"
end
That's the solution I copied in the registrations controller the new method and named it new_facebook and now everything is working as expected !
I think the issue is that you're not overriding the devise method that redirects to that path. Also according to the devise docs your routes should be set up with a "devise_for" call.
Here's the wiki page describing how to do what you are asking to do, although you may need a bit of custom logic to deal with cases that aren't facebook signups.
https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-up-(registration)
Some example code from that page:
class RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
'/an/example/path'
end
end
and the one for routes:
devise_for :users, :controllers => { :registrations => "registrations" }

Devise + Facebook Omniauth Error on redirect

I am using devise, omniauth & facebook-omniauth for my Rails 3.1 app. After authentication I wanted to redirect the user to the page was viewing. I have used the following code for the same:
def facebook
#user = Spree::User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = "Yipee! You were successfully authorized from your Facebook account!!"
sign_in #user, :event => :authentication
redirect_to request.referrer
end
This gives me the following error only at the time of user creation:
ActionController::ActionControllerError in Spree::OmniauthCallbacksController#facebook
Cannot redirect to nil!
The following times when the user has already been created, no errors are shown during & after log in.
How do you suggest I fix this? Thanks!
you can overwrite the functions for sign in/ sign up path in your application controller:
def after_sign_up_path_for(resource)
credit_path
return request.env['omniauth.origin'] || session[:return_to]
end
def after_sign_in_path_for(resource)
return request.env['omniauth.origin'] || session[:return_to]
end
use sessions to store the current path in the path that you want them to go to: session[:return_to] = request.url #store current location
or you create a method that will always be called once they go to a path and store that location. watch out for a giant loop redirection when you do that though.

Rails remember_token session not working

I am new to Ruby on Rails. I am learning it through Michel Hartl's reference doc available on the internet. However i ran into a problem during sign-in of users, I suspect the before_save is not calling the create_remember_token method. I am trying to debug this issue from a very long time. My code is as follows:
user.rb file:
# == Schema Information
#
# Table name: users
#
# id :integer(4) not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# password_digest :string(255)
# username :string(255)
# remember_token :string(255)
#
class User < ActiveRecord::Base
def to_param
username
end
attr_accessible :name, :email, :password, :password_confirmation, :username
has_secure_password
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
session_helper.rb
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= user_from_remember_token
end
def signed_in?
!current_user.nil?
end
private
def user_from_remember_token
remember_token = cookies[:remember_token]
User.find_by_remember_token(remember_token) unless remember_token.nil?
end
end
sessions_controller.rb:
class SessionsController < ApplicationController
def new
end
def create
user=User.find_by_username(params[:session][:username])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to "/#/#{params[:session][:username]}"
else
flash.now[:error] = "Login failed! Please try again!"
render 'new'
end
end
def destroy
end
end
Please help me and let me know as to where the problem exists.
Cheers :)
What exactly is the problem that you are having during sign in?
The reason I ask is that the create_remember_token method is not supposed to be called during the sign-in process. It gets called when the user is saved (sign-up).
The sign-in process just fetches the token from the users table and copies it into the permanent cookie. The sign-in process looks roughly like this:
sign_in user --> session_helper.rb --> def sign_in(user) --> cookies.permanent[:remember_token] = user.remember_token --> back to session_controller.rb --> redirect_to ...
The before_save callbacks should only be called when the user is created (ie. when they sign up, not when they sign in). You don't show the whole sign-up/user creation flow in your code sample, but i assume it exists.
You can test whether create_remember_token is called (when the user is created) by running this command from the Rails console:
User._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:create_remember_token)
That should return true if and only if the create_remember_token function is being run on save. More details in the 'Debugging callbacks' section of the Callbacks API Documentation.
If the callback is called during the signup flow, the remember_token should be saved to the DB then. You can verify that by inspecting the user with the Rails console (User.last, after creating your test user).
What does your sign-up/user creation flow look like? What repro steps produce the problem you're describing?
You might have not used csrf meta tag in your layout. Try removing ' protect from forgery ' in application_controller.rb in controllers folder. Then try running the app again, if it works then you didnt add tags to your layout.
I had posted this question a year ago.
Now I am using the Devise gem for authentication. Everything is working as expected.
Thanks

Rails redirect issue - Hartl's Rails Tutorial 10.2.3

I'm a complete noob working through Michael Hartl's (awesome) Rails tutorials, and have an issue with the friendly redirect in Ch.10.2.3. The purpose is to try to store the location, redirect to the sign in page, then redirect back to the original intended destination when sign-in is complete. My problem is that it simply renders the standard user profile page after signing in/creating a session, rather than redirecting.
I have this in the sessions_controller:
def create
user = User.authenticate(params[:session][:email],
params[:session][:password])
if user.nil?
flash.now[:error] = "Invalid email/password combination."
#title = "Sign in"
render 'new'
else
sign_in user
redirect_back_or user
end
end
And this in sessions_helper:
def authenticate
deny_access unless signed_in?
end
def deny_access
store_location
redirect_to signin_path, :notice => "Please sign in to access this page."
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
clear_return_to
end
private
def store_location
session[:return_to] = request.fullpath
end
def clear_return_to
session[:return_to] = nil
end
I'm sure I've yet again made a stupid, simple mistake but I can't find it.. help?
The code is available here: https://github.com/railstutorial
Consider making a new git branch (or new project) for yourself that uses just this repository's code. Then you will have a working local version for comparison when things go wrong.