So i've built my first app using Devise! I'm pretty stoked, but I would like to know how one goes about having the app re-direct to a specific page after logging in?
In other words,
Instead of logging in, and remaining at the home page, how do I get rails to redirect to a microposts page for example?
In my case specifically it only redirects to the posts page sometimes, and other times it just stays at the initial home page.
Here is my posts controller:
class PostsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
def posts
#title = "Posts"
end
end
By default, devise redirects you to the root, you can customize after_sign_in_path_for method anyway you like. There's also after_sign_out_path_for method at your disposal to customize.
ApplicationController < ActionController::Base
# extra stuff
def after_sign_in_path_for(user)
if something
posts_path
else
root_path
end
end
def after_sign_out_path_for(user)
new_some_other_path
end
end
Related
I want one pages of my ruby on rails web application inaccessible to one of my STI model types. I have two models typeA and typeB inheriting from User. I have used the column type in the User table to implement STI. I am using Devise gem for User sessions. I want one webpage 'http://localhost:3000/rate' inaccessible to my typeA User. Whenever an User logs in who is of the type 'typeA', he does not have the option of seeing the link 'Rate'. But I also do not want him to be able to access that page by the link 'http://localhost:3000/rate'. If he tries to access it through that link, I want to sign him out and make him log in again.
I managed this by using a piece of code in my Controller with the specific method for 'rate'.
def rate
if current_user.type == "typeA"
sign_out(current_user)
redirect_to new_user_session_path
else
#Code for User of typeB
end
end
This is working but I wanted to know if this can be done in a better way using before_filter :authenticate_user! or something else
Right now my before_filter part looks like this
before_filter :authenticate_user!, except: [:index, :show]
Is there any way I can make a change to the upper code to achieve that functionality.
P.S: Maybe this can be done better if I had used roles or other gems like CanCan/Pundit but I do not have much time left to submit my project, so I do not want to get into all that right now.
you can add another before_filter on the controller you want to restrict the access just to confirm your STI user type without overiding devise's authenticate_user! filter.
application_controller.rb
class ApplicationController < ActionController::Base
def confirm_user_type(user_type)
redirect_to new_user_session_path unless current_user.is_a?(user_type)
end
end
pages_controller.rb
class PagesController < ApplicationController
# must be authenticated to access
before_filter :authenticate_user!
# must be user of TypeA to access
before_filter { |c| c.confirm_user_type(TypeA) }
def rate
...
end
end
Then, you can use the same filter before_filter { |c| c.confirm_user_type(TypeB) } for STI user type: 'TypeB'
Try this:
class ApplicationController
before_action :authenticate_user!
def authorize_user!
if current_user.type == "typeA"
sign_out(current_user)
redirect_to new_user_session_path
end
end
end
with your controller:
class SomeController < ApplicationController
before_action :authorize_user!, except: [:index, :show]
def top_secret
...
end
end
I believe if a before_action (the new name for before_filter) renders or redirects, the action won't be processed.
I have a Ruby on Rails web application, where a user needs to provide his nickname and password to register. After successful registration, the user is redirected to an edit page, where he should enter his email.
The use case requires to always redirect the user to the edit page until he has submitted a valid email address. However, in the current state, the user can click on any menu item and is then taken to the corresponding page. How do I prevent this behavior and redirect the user back to the edit page when clicking on a menu link?
You can create a before_action in your ApplicationController which checks if the user is logged in and has submitted his email, something like this:
class ApplicationController < ActionController::Base
before_action :validate_email_confirmed
def validate_email_confirmed
return unless current_user
redirect_to user_edit_path unless current_user.email?
end
end
Keep in mind that you have to skip this before_action for both the user edit and update actions, or you'll end up having a redirect loop. This is how to skip an existing before_action for specific actions:
class UsersController < ApplicationController
skip_before_action :validate_email_confirmed, only: [:edit, :update]
end
Did some more digging, and found this on the official docs, seems to fit your needs:
class ApplicationController < ActionController::Base
before_action LoginFilter
end
class LoginFilter
def self.before(controller)
unless controller.send(:logged_in?)
controller.flash[:error] = "You must be logged in to access this section"
controller.redirect_to controller.new_login_url
end
end
end
You'd of course have to rework this some, to get awaiting_email or such, but the principle is the same.
I have a login page saving a session to allow users to navigate subsequent pages. If you're not logged, I want to redirect you to the log in page. I have a SessionsHelper method for checking if the user is logged in and then if not, redirecting them back to the login page, But I don't want to have to call this in every controller action. Is there a way to easily run this method globally?
Traditionally this is done via a before_action filter. Something along these lines:
class ApplicationController
before_action :require_current_user
def require_current_user
redirect_to login_path unless current_user
end
end
class SessionsController < ApplicationController
# do not cause endless redirect loop
skip_before_action :require_current_user, only: [:new, :create]
end
Also, helpers are for simplifying views (currency formatting, styling, etc.). They are not to be used for this kind of functionality (session management, in this case).
I'm trying to set up something that allows users to go to certain urls only under certain circumstances. Right now I have a setEvent/:id url that sets a property on users to an event_id, then redirects the user to the event url. The user can access a url like .../whatever/event/1 where 1 needs to equal the event_id, and if it doesn't it redirects the user.
However, this doesn't stop someone from just typing .../whatever/setEvent/:id into their address bar to get access to the page.
The proper way to do this is with a before action in your controllers. Here is an example from one of my apps where a user who is not logged in will always be redirected to the new_session URL.
class ApplicationController < ActionController::Base
helper_method :current_user, :logged_in?, :herd_user
def herd_user
redirect_to new_session_url unless logged_in?
end
... other medthods...
end
and
class StaticPagesController < ApplicationController
before_action :herd_user
def index
end
end
without bringing in more gems you can just do a before_action
before_action :enforce_tenancy, except: [:index]
before_action :allow_only_admin, only: [:index]
private
def enforce_tenancy
render unauthorized unless event.user_id == current_user.id
end
def allow_only_admin
render no_way_sucka_path unless current_user.admin?
end
I had a similar problem and this might not be the best way to handle it but in the action for that page you can check the current url and check the property then redirect to the one they can access if they go to an incorrect url.
Something kind of like:
url_id = request.fullpath.sub('/whatever/event/', '')
redirect_to user_page_path(user.id) unless (current_user.event_id.to_s == url_id)
Sorry if the code isn't great I tried to write it based off of the info you gave.
Edit* Make sure to do this before getting any info for the page from your database or it will be less efficient.
I've set a fake user to demo my app. The idea is that visitors, who won't be signing in, should still be able to see all the functionality that a real user would have. When a non-logged-in visitor hits the site, the app will sign in the demo user and visitors will see fake data belonging to this demo user.
With this goal in mind, I setup my application controller like this.
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_current_user
def demo_user
#demo_user ||= User.find_by_email("demo#example.com")
end
protected
def set_current_user
if current_user.nil?
sign_in(demo_user)
end
end
end
My problem is that I accidentally made it impossible for real users to sign in. Anytime a real user presses the "sign in" link, they're told that they're already signed in (as the demo user).
So clearly, what I've done is nowhere close to a "best practice." What would a smart programmer do in this situation? How do I keep my nifty automatically signed in demo user but still leave the door open to real users to sign in?
You need to add an :except to your :before_filter so that it doesn't run on the sign_in action, whatever it may be. Assuming you're using devise, that would be SessionsController#new, so it would look like:
before_filter :set_current_user, :except => :new
Note that this will skip the filter for all 'new' actions, so a more targetted way of doing it would be (again, assuming you are using Devise) to create a custom SessionsController which inherits from Devise::SessionsController and leave it blank except for:
skip_before_filter :set_current_user, :only => [:new, create]
Your set_current_user function is in a before_filter which means it runs once for every request. The current_user will be nil the first time anyone visits and so they will be signed in as the demo user. You can skip the before_filter for your sessions_controller#create action (or whatever it's called in your app. For example, if you are using Devise:
class SessionsController < Devise::SessionsController
skip_before_filter :set_current_user, :only => :create
end
Here's what I ended up with. I started off with Omnikron's solution, but I needed a little more.
This post helped: https://groups.google.com/forum/#!msg/plataformatec-devise/0WylcwjSAJY/ITDF6kFjJvwJ.
class SessionsController < Devise::SessionsController
skip_before_filter :set_current_user, only: [:new, :create]
skip_before_filter :require_no_authentication, :only => [:new, :create]
def new
if user_signed_in?
sign_out current_user
redirect_to new_user_session_path
else
super
end
end
end