Devise is behaving strangely. It shows the red or the error messages, but it does not show the green or success messages.
This happened after I made changes to the routing and controller to redirect to sign-in page or home page according to whether the user is signed-in or not.
So the routes.rb now has:
devise_for :users
root :to => "questions#redirect_on_visit"
match 'home', :to => "questions#index"
and the controller:
before_filter :authenticate_user!, :except => [:redirect_on_visit]
def redirect_on_visit
if user_signed_in?
redirect_to home_path
else
redirect_to new_user_session_path
end
end
Also changed application controller to redirect to appropriate pages after sign-in/sign-out:
protected
def after_sign_in_path_for(resource)
stored_location_for(:user) || root_path
end
private
def after_sign_out_path_for(resource)
stored_location_for(:user) || root_path
end
I was being extremely numb. The fact that I have root :to => "questions#redirect_on_visit", will redirect each time a user visits, signs in or signs out. Redirect was clearly washing away the flash messages.
Finally I found the solution I was looking for. It is to preserve the flash messages flash.keep(:notice) as mentioned here.
Your problem is the multiple redirection from login => root => home
as flash object has a life leave only for a single request
I guess It would be better of writing redirect_on_visit routing in after_sign_in_path_for and after_sign_out_path_for
something like this
def after_sign_in_path_for(resource)
stored_location_for(:user) || home_path
end
private
def after_sign_out_path_for(resource)
stored_location_for(:user) || new_user_session_path
end
Related
I'm looking for a solution.
I'm trying to redirect users when they are not an admin.
I've done that :
def is_admin?
if current_user.admin?
redirect_to action: "index"
else
redirect_to root_path
end
end
I have before_action :is_admin? in my posts_controller
I dunno why exactly, but the redirection not working. Firefox gives me a blank page with:
The page is not redirected correctly
Thanks for your help
The problem is your before_action :is_admin? which call is_admin? on index methods and keep redirecting on themself...
I don't understand why redirecting on 'index', you should instead change your method is_admin? like :
def is_admin?
# redirect ONLY if user isn't admin
redirect_to root_path unless current_user.admin?
end
I have a users_controller.rb. There are too many method including login, register, forgot_password and logout I want to put auth allow these actions in my ruby controller.
I have done $this->Auth->allow in the CakePHP.
$this->Auth->allow('register', 'login', 'forgot_password', 'logout');
But in the ruby this is very hard to put. Please suggest me -
def login
#title = 'Login'
#render layout: 'login'
end
def dashboard
if logged_in?
#title = 'My Dashboard'
#user = User.get_profile(session[:user_id])
#user = User.get_profile(session[:user_id])
#raise #myProfile.inspect
else
redirect_to '/login'
end
end
def my_profile
if logged_in?
#title = 'My Profile'
#user = User.get_profile(session[:user_id])
else
redirect_to '/login'
end
end
def logout
log_out
redirect_to '/login'
end
Each time I am adding if logged_in? ... else ... end in my every action. So
I want to put Auth Allow in ruby like CakePHP code. Please help me.
Those actions should be in separate controllers, there are plenty of resources available to explain this, search for "RESTful Rails".
Once they are in separate controllers you can use a "before" action to prevent unauthorised users from accessing those actions.
It looks like you've created your own authentication system, instead of using a gem, so if you want a method to check for a logged in user, you can add it.
In application_controller.rb
def authenticate_user
redirect_to login_path unless logged_in?
end
Then in any controller you want to require a user to be signed in you can do
class YourController < ApplicationContoller
before_action :authetnicate_user, except: [:actions_that_doesnt_need_auth]
...
# All normal methods
end
That being said - the previous answer about using RESTful resources is important to understand and keep in mind. If you have questions you can ask :)
Using before_action :authenticate_user! to check if user logged in. But it sends users to login instead of signup.
Tried different ways of directing user to signup instead of login, but they do not send the user back to the original page after successful signup.
How can I send a user to signup and direct a user back to the original page afterwards?
Attempts:
before_filter :auth_user
def auth_user
redirect_to new_user_registration_url unless user_signed_in?
end
Routes File
Rails.application.routes.draw do
devise_for :installs
resources :orders
resources :products
devise_for :users
get 'dashboard' => 'pages#dashboard'
get 'contact' => 'pages#contact'
get 'cart' => 'carts#index'
root 'pages#home'
What you are looking for is a referer.
Having your before_filter working, you can override the Devise's after_sign_up_path_for:
def after_sign_up_path_for(user)
request.referer
end
EDIT
Since request.referer is somehow not working, I think you could go with a session-based solution:
def auth_user
session[:before_sign_up_path] = request.fullpath
redirect_to new_user_registration_url unless user_signed_in?
end
def after_sign_up_path_for(user)
session[:before_sign_up_path]
end
Devise uses warden for authentication. Thus to override the whole behavior you have to override the way devise asks it to handle authentication failures.
Create a class that extends Devise::FailureApp
class RedirectToSignUp < Devise::FailureApp
def redirect_url
new_user_registration_url
end
def respond
if http_auth?
http_auth
else
redirect_to new_user_registration_url
end
end
end
Add this to your devise initializer config/initializers/devise.rb
config.warden do |manager|
manager.failure_app = RedirectToSignUp
end
I believe this will solve your problem and will redirect you to the page you were at since you are overriding only the redirect route.
I haven't tried it but this seems to be what you are looking for. Note that it says that it is out of date. So you should see the source code if you want to understand what's going on.
Navigating through the source code of Devise(this and this) my guess is that you can extend Devise::RegistrationsController and then override the method after_sign_up_path_for to be stored_location_for(:user) || root_path.
the way I like to set up my users area using devise is:
# config/routes.rb
devise_for :users, :controllers => {
registrations: 'users/registrations',
sessions: "users/sessions",
passwords: 'users/passwords',
confirmations: 'users/confirmations'
}
authenticate :provider do
namespace :providers do
....
end
end
Then I have a controller that manages all other users controllers like this
#app/controllers/user_controller.rb
class UserController < ApplicationController
before_filter :authenticate_user!
layout 'users/default'
before_filter :check_user_active
private
def check_user_active
unless current_user.active
flash[:notice]= t(:user_not_active)
sign_out current_user
redirect_to new_user_session_path
end
end
end
all my other user controllers look inherit from it like
#app/controllers/users/users_controller.rb
class Users::UsersController < UserController
...
end
I hope that this helps.
This is very simple
User store_location_for method
Like
before_filter :auth_user
def auth_user
unless user_signed_in?
store_location_for(:user, request.fullpath)
redirect_to new_user_registration_url
end
end
How would one render a page say a "/logout" page that displays a "Thanks for visiting us" then if the user reloads the browser it would load "/" instead?
I have a
match "/logout" => "home#logout"
But don't wan't anyone that requesting "/logout" will see this page, it should only be rendered direct after the user is signed_out.
What would be the best way to approach this render a view dependant with a conditional redirect ( to root_path) instead of using a redirect_to
You probably want:
match '/logout' => 'sessions#destroy', :via => :delete
And use logout_path in your link_to helper or however you decide to implement logging out in your application.
And write your message in the flash in SessionsController#destroy. It may look something like:
class SessionsController < ApplicationController
def destroy
sign_out # or whatever you named your method for signing out
flash[:notice] = "Thanks for visiting us"
redirect_to root_path
end
end
In order to make sure the request goes to root_path when the user is not signed in, you should place a before_filter in ApplicationController:
class ApplicationController < ActionController::Base
before_filter :authenticate_user
def authenticate_user
unless signed_in?
redirect_to root_path
end
end
helper_method :authenticate_user
end
This way, after the user is signed out, all requests will redirect to root_path.
To allow requests to pages without being signed in, use skip_before_filter in the appropriate controller classes:
def MyPublicStuffsController < ApplicationController
skip_before_filter :authenticate_user
# ...
end
a user of my website must first login to see every page of it. My current solution results in a "too many redirects" error message in the browser, I suspect something goes wrong so it endlessly goes back and forth, but where?
In the application controller I have this:
before_filter :authenticate_user
def authenticate_user
unless session[:user_id]
flash[:alert] = I18n.t :session_unauthenticated
redirect_to login_path
end
end
The "login_path" goes to "sessions/new", which looks like this:
def new
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, :notice => I18n.t(:session_logged_in)
else
flash.now.alert = I18n.t(:session_invalid)
render "new"
end
end
Thanks for your help!
Your before_filter is active for each and every action (since it's in the ApplicationController) and therefore also for your sessions#new action. Meaning you cannot even enter the login action. I suggest you put the before_filter in every needed controller and specify the actions with before_filter :authenticate_user, :except => [:new, :create, :destroy] or whatever you need.