I've a current_user method to handle authentication.
application_controller.rb
protect_from_forgery
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
but when I try to acces a to a page I get the following error:
Couldn't find User with id=1
app/controllers/application_controller.rb:10:in `current_user'
How can I pass #current_user a sort of default value so if there's no user it will redirect to login page.
Thanks for helping.
It looks like your session contains old data, specifically an id (1) of a user which no longer exists. Try handling the RecordNotFound exception raised by ActiveRecord, and returning nil:
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
rescue ActiveRecord::RecordNotFound
end
To redirect, you should add a second before_filter which checks for a user and handles redirecting to the login path:
before_filter :require_user
def require_user
redirect_to login_path unless current_user
end
Remember to omit require_user for your login action by adding skip_before_filter :require_login to whichever controller manages your authentication.
Related
Ryan Bates gives great screencast http://railscasts.com/episodes/360-facebook-authentication how to use "omniauth-facebook" gem. But there is some issues with:
#application_controller.rb
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
It sets #current_user too late for standart Devise auth protection for actions in controllers:
before_filter :authenticate_user!, :except => [:index, :show]
So it redirects to sign in page, even #current_user is aviable in views...
Maybe anyone knows how to fix it?
PS I saw few tricks with redirects handler, but I think there should be better decision...
I have found the simple way to sign in using standart Devise method. Based on this tutorial, just set code in sessions_controller:
#sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
sign_in user
redirect_to root_url
end
end
And you can delete this from application controller:
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
I've been trying to get authentication working with devise, and then omniauth, but I haven't been able to get the user session.
In my application controller, I have
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
end
which I got from the updated railscast https://github.com/railscasts/241-simple-omniauth/blob/master/revised/blog-after/app/controllers/application_controller.rb
In my app, I call
<% if current_user %>
but this always errors out as undefined local variable or method 'current_user'
why is this? is it a problem with my application controller, or maybe a session error with rails?
I'm using before_filter in my application. I have a method logged_in? which returns true if the user is logged in.
def logged_in?
!!current_user
end
def current_user
#current_user = (User.find(session[:user_id]) if session[:user_id]) || false
end
Now in my users controller I want an action to execute only if a user is not logged in. For this I want to use the not condition with logged_in? method in before_filter as:
before_filter :!(logged_in?)
But this gives me an error. I'm resisting creating a new method for not logged in.
Please help me figure out the correct syntax to accomplish this.
While the accepted answer seems to work, I would have done it differently.
before_filter :login_required, unless: :logged_in?
def login_required
redirect_to login_path, notice: 'Please login'
end
This will execute the method login_required unless the user is already logged in. See http://robots.thoughtbot.com/post/159805303/before-filter-wisdom for more info.
You could pass a block to before_filter:
before_filter { |c| !c.logged_in? }
But this wouldn't really do anything, since the return value from the before filter isn't going anywhere. If you want to execute an action if a user is not logged in, then you should be putting that action into the before_filter.
For example, if the action was to redirect to the login page, path, you could do this:
before_filter { |c| redirect_to login_path unless c.logged_in? }
That's actually long enough to justify a method of its own:
before_filter :login_required
def login_required
redirect_to login_path unless logged_in?
end
application_controller.rb
before_filter :authorize
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
helper_method :current_user
protected
def authorize
unless User.find_by(id: session[:user_id])
redirect_to login_url, :notice => "Not Authorize Member"
end
end
I have a Rails 3.2.3 application and I am using MiniTest and Capybara to run my integration tests. I rolled my own authentication and created a current_user helper_method in my application_controller.rb.
My application layout file only displays certain links, like logout, etc., when a user is logged in.
But the current_user method does not work during tests. It looks like this:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def authenticate
if current_user.blank?
redirect_to root_url, :alert => "You must first log in."
end
end
def authenticate_admin
unless current_user and current_user.admin?
redirect_to root_url, :alert => "You must be logged in as an administrator to access this feature."
end
end
def current_user
begin
#current_user ||= User.find(session[:user_id]) if session[:user_id]
rescue
nil
end
end
helper_method :current_user
end
So in my application.html.erb file there is:
<% unless current_user.blank? %>
<li><%= link_to logout_path %></li>
So this works when I test it through the browser, but not in my test. "current_user" ends up being nil.
I am new to BDD, but is there something that prevents sessions from being created during tests? What am I missing?
NOTE: helper methods defined in controllers are not included.
from here.
The solution is to organize them in a dedicated helper class.
I am using devise and create login with Facebook using omniauth, but having problem of lost the devise helper methods access like current_user and user_signed_in? methods are not working.
EDIT
AuthenticationController
def create
omniauth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(omniauth["provider"], omniauth["uid"]) || User.create_with_omniauth(omniauth)
session[:user_id] = user.id
redirect_to dashboard_path(user.id), :notice => "Signed in!"
end
redirect_to USercontroller dashboard method
UserController
before_filter :logged_in
def dashboard
#user = User.find(params[:id])
#comment = Comment.new
#comments = #user.comments.all.paginate(:page => params[:page], :per_page => 5)
end
so here control should go to dashboard method after checking logged_in method in ApplicationController
logged_in method in ApplicationController
Application Controller
def logged_in
if user_signed_in?
return true
else
redirect_to root_path
flash[:message] = "please login"
end
end
when I logged in using facebook following code generated at console
Started GET "/users/52/dashboard" for 127.0.0.1 at Thu Mar 29 12:51:55 +0530 2012
Processing by UsersController#dashboard as HTML
Parameters: {"id"=>"52"}
Redirected to http://localhost:3000/
Filter chain halted as :logged_in rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.0ms)
in the above code control is render from logged_in method to root_path but it shold render dashboard_path
So I am guessing User_signed_in? helper is not working I also use current_user in stead of that generate same error
As I see, user_signed_in? is working, but returns false, as for Devise user is not logged in. To fix this, just replace the session id storing with Devise sign_in method in your controller action:
def create
omniauth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(omniauth["provider"], omniauth["uid"]) || User.create_with_omniauth(omniauth)
sign_in(:user, user)
# actually if you really really need that id in the session, you can leave this line too :)
session[:user_id] = user.id
redirect_to dashboard_path(user.id), :notice => "Signed in!"
end
After creating the user account via Facebook, how do you sign in the user?
You should still be using devise helpers like sign_in_and_redirect. Something like:
user = User.build_from_omniauth(omniauth)
if user.save
sign_in_and_redirect(:user, user)
end
Then you should be able to use helpers like current_user and user_signed_in? (which just check if current_user is not nil).
Taking a look at your edit, my answer is still valid. What you need to do is use sign_in_and_redirect(:user, user) instead of just setting the id in the session.
You can easily customize where the user is redirected after sign in with devise.
Another thing, remove this logged_in filter, Devise has a authenticate_user! method that you can use as a before_filter. It will redirect the user to the sign in page, and when they login, it will redirect them to the page they were trying to access.
You're using Devise, so try to take advantage of that, and go read the doc ;)