I am new in Ruby on Rails and i am using Ruby version 1.9.3 and Rails version 4.0.2.
My Query is:-
How to create `authenticate_user' method without devise in Ruby on Rails.
Below my routes
get "admin/users/sign_in" => "admin/users#sign_in"
Below My Application Controller:-
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
rescue_from CanCan::AccessDenied do |exception|
flash[:alert] = "Access denied. You are not authorized to access the requested page."
redirect_to root_path and return
end
helper_method :current_user
before_filter :authenticate_user, :current_user
def current_user
# Note: we want to use "find_by_id" because it's OK to return a nil.
# If we were to use User.find, it would throw an exception if the user can't be found.
#current_user ||= User.find_by_id(session[:user_id]) if session[:user_id]
#current_user ||= User.find_by_authentication_token(cookies[:auth_token]) if cookies[:auth_token] && #current_user.nil?
#current_user
end
def authenticate_user
if #current_user.nil?
flash[:error] = 'You must be signed in to view that page.'
redirect_to :admin_users_sign_in
end
end
protected
#derive the model name from the controller. egs UsersController will return User
def self.permission
return name = self.name.gsub('Controller','').singularize.split('::').last.constantize.name rescue nil
end
def current_ability
#current_ability ||= Ability.new(current_user)
end
#load the permissions for the current user so that UI can be manipulated
def load_permissions
#current_permissions = current_user.role.permissions.collect{|i| [i.subject_class, i.action]}
end
end
Below code using my controller
before_filter :authenticate_user!
My authenticate_user method not redirect properly
redirect_to :admin_users_sign_in
admin_users_sign_in path define in routes see on top
Above the code every time say on browser "The page isn't redirecting properly"
Please help
I suspect the problem is due to this line:
redirect_to :admin_users_sign_in
You need to pass either an action & controller or a friendly name of the path to redirect_to.
Change your routes to be something like
get "admin/users/sign_in" => "admin/users#sign_in", :as => :admin_user_signin
Then you can do something like
redirect_to admin_user_signin_path
This looks an infinite loop.
You defined authenticate_user at ApplicationController level. So, when a visitor visited page 'foo', he is denied by this method because current_user is nil. Then he got redirected to admin sign in page, but that page has this before_filter as well, so he got redirected again, to the same page and never end.
To fix, move such filter to specific controllers which need protection. And do not set it in sign in/sign up page.
Side notes:
You've already used CanCan which has authorization on "read" as well. There is no point to use authenticate_user again for same functionality.
Related
I'm working on a login/logout system. Instead of using devise, I created an active records User model and use sessions to remember if a user is logged in. Everything was working fine until I added these lines in the application_controller.rb to have a layout before login and one after.
layout :set_layout
def set_layout
if session[:current_user_id]
'afterlogin'
else
'application'
end
end
Now, after I log in and cancancan is being used somewhere in a html page I get undefined local variable or method 'current_user'. I think that I have to add a current_user method but I'm not exactly where and how to define it.
Edit: I already had something similar in another class that is being used by login:
class Admin::ApplicationController < ApplicationController
before_action :authorize
def authorize
begin
#current_user ||= User.find(session[:current_user_id]) if session[:current_user_id]
rescue ActiveRecord::RecordNotFound
session.destroy
redirect_to '/login',alert: 'Please login'
end
end
end
Should I modify this after I add that method ?
CanCanCan expects a current_user method to exist in the controller.
First, set up some authentication (such as Authlogic or Devise).
See Changing Defaults if you need different behavior.
I would suggest you to install Devise so that it comes with a complimentary current_user method.
FYI: https://github.com/plataformatec/devise
UPDATE
when a user logins successfully, you can store the user's id in session.
session[:current_user_id]=user.id
so that, in your applicationcontroller, you can do
def current_user
#current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id])
end
helper_method :current_user
I am trying to implement a survey using the surveyor gem in rails. I want to make use of the user id to keep track of which user creates the survey and which user gave what response on which survey.
The problem is that I did not use the Devise gem for my user signin and signup. I built it manually. The surveyor gem uses a helper method current_user of Devise which returns details about the current user.
Since, I did not use devise, I am not sure where to add the helper method current_user.
I am not really sure as to what code to post, so please comment the required details. I will edit my post as needed.
Thanks!
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :authorize
helper_method :current_user
protected
def authorize
return true if ((self.class == SessionsController)|| (self.class == UsersController && (self.action_name == "new" || self.action_name == "create")))
unless (User.find_by_id(session[:user_id]))
redirect_to url_for(:controller => :sessions , :action => :new), alert: "You need to be logged in."
end
end
def current_user
#current_user = User.find(session[:user_id])
end
end
Here is the link of the surveyor gem controller which uses the current_user method: https://github.com/kjayma/surveyor_gui/blob/master/app/controllers/surveyor_gui/survey_controller.rb
Here is one possible solution to implement a current_user method.
helper_method would make the current_user method available in every controller, which inherits from ApplicationController.
class ApplicationController
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
How do I guarantee that users only access the routes on my web app if they are logged in? I already have Users and Session models and users are able to create accounts. But how do I make sure that if they are not logged in they are always redirected to the login/sign up page, but if they are they have access to all the routes?
EDIT: So this is what my Application Controller looks like right now:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
So if there isn't a current user, I want to allow access only to the my Pages controller and its actions (which are basically home, signup, login, etc.). If there is a user, on the other hand, I want that user to be able to access all the routes in my route file.
class SomeController < ApplicationController
def show
if current_user.nil?
redirect_to '/path/to/login'
end
end
end
could probably give a more detailed answer if you paste in some code otherwise we all are just guess what your methods are called.
If you are using devise it comes with the built in helper method authenticate_user! which should be placed in your application controller.
If you are not using devise you can define you own method (for this example I will copy devise) authenticate_user! in application controller and call the before action
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
hide_action :current_user
private
def authenticate_user!
redirect_to :root if current_user.nil?
end
end
I am new in Ruby on Rails and i am using Ruby Version 1.9.3 and Rails version 4.0.2.
My query is:
How to get controller and his action name with router prefix in application controller?
See Below my code:-
See Router
root :to=>"home#index"
get "admin/" => "admin/users#index"
get "admin/sign_in" => "admin/users#sign_in"
get "sign_in" => "admin/users#sign_in"
See my application controlle
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user
rescue_from CanCan::AccessDenied do |exception|
flash[:alert] = "Access denied. You are not authorized to access the requested page."
redirect_to root_path and return
end
before_filter :current_user, :get_model
def current_user
# Note: we want to use "find_by_id" because it's OK to return a nil.
# If we were to use User.find, it would throw an exception if the user can't be found.
#current_user ||= User.find_by_id(session[:user_id]) if session[:user_id]
#current_user ||= User.find_by_authentication_token(cookies[:auth_token]) if cookies[:auth_token] && #current_user.nil?
#current_user
end
def authenticate_user
#mydata = params
if current_user.nil?
flash[:error] = 'You must be signed in to view that page.'
redirect_to :admin_sign_in
end
end
end
def authenticate_user method i have create in application controller.
I want
if current_user.nil? and router prefix is admin Like localhost:3000/admin
it will be redirect on admin sign in path
redirect_to :admin_sign_in
Other then it will be redirect front end sign in part
redirect_to :sign_in
Update my question
My query is how to set condition according to controller and action name with namespace in authenticate_user method where redirect to page.
Please help. How it is possible?
Use namespaces in your routes.
http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing
especially chapter 2.6
2.6 Controller Namespaces and Routing
You may wish to organize groups of controllers under a namespace. Most commonly, you might group a number of administrative controllers under an Admin:: namespace. You would place these controllers under the app/controllers/admin directory, and you can group them together in your router:
namespace :admin do
resources :posts, :comments
end
Also call admin_sign_in_path or sign_in_path instead of symbols. to see all routes in you app use rake routes .
When a user visits a page that they are not authorized to view they get redirected to the login page. After they log in they are redirected to the site root. Is there a quick and easy way to redirect them back to the page they initially asked for?
You could add a hidden field referring_page to your sign_in-form to add the former referrer to that field and route back to there if its existing, like this:
def after_sign_in_path_for(resource)
params[:referring_page] || super
end
It's a manual solution but i prefer it to using complex logic on controller side.
I dont understand what you exactly want to achieve by saying "if a user visits a page that they are not authorized to view they get redirected to the login page. After they log in they are redirected to the site root"
I assume there will be two sets of users one is admin- user and another is non-admin user the way i handle this will be something like this,
Inside application controller
class ApplicationController < ActionController::Base
protect_from_forgery
check_authorization :unless => :devise_controller?
before_filter :authenticate_user!
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
end
protected
def stored_location_for(resource_or_scope)
nil
end
def after_sign_in_path_for(resource_or_scope)
if current_user.admin?
#add your desired path
else
#redirect to your desired path
end
end
end