How to make devise not require authentication for home page? - ruby-on-rails

I have before_action :authenticate_user! in the application controller, which is very efficient because it applies to all controllers but there's one page (home page) that should be available without login.
Is there a way to keep before_action :authenticate_user! in application_controller.rb (for the sake of DRY) and make an exception to allow access to just home#home to be available without authentication?
Notes:
we could obviously remove before_action :authenticate_user! from the application controller and place it in all controllers but for 'home#home' (the downside to this is it's not very DRY)
just a side note, but I'm not exactly sure why the /users/sign_in url is even accessible (something in devise must make it so, but I'm not sure where that mechanic lives or what it is exactly - perhaps if I found it I could add more routes to it?)

You want to skip the before_action using skip_before_action
In the controller for that page put
skip_before_action :authenticate_user!, only: [:home]
This specifies it just for that one action, if all the pages in that controller need to be skipped you can just use
skip_before_action :authenticate_user!

Related

Ruby - Automatically running helper method

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).

How to make a public page in an app that uses devise

I'm using devise for Authentication in a Rails 4 app. Almost all of the app requires a user to be authenticated, however, there are a few 'public' pages (Terms and conditions - that kind of stuff).
Devise itself makes the sign up and sign in pages public, using prepend_before_filter :require_no_authentication. However, that method is intended only for devise controllers. And devise doesn't seem to provide a 'proper' way to make single actions public.
So, what's the best way to make just a couple of actions public?
The only ways I can think of so far is:
To make a new public namespace, and have separate controllers for public actions, which inherit from a PublicController that does not execute before_filter :authenticate_user!
Same as above, but ditch the inheritance and the namespace. So the PublicController could act as a bucket for anything that needs to be public - which at this stage isn't much.
Is there a better way to make individual actions public with devise?
You can optionally use skip_before_action for the public controllers. Example from guides:
class LoginsController < ApplicationController
skip_before_action :require_login, only: [:new, :create]
end
In your controller, you want to have:
before_action :authenticate_user!, :except => [:index]
This will perform the :authenticate_user! method on all actions except index action.
You can find more explanation in this answer.

Using Devise before_action :authenticate_user! doesn't do anything

I am trying to require login on all pages on my Rails 4 web site.
In the ApplicationController I have added before_action :authenticate_user!, but it simply doesn't do anything. I have tried to add the same before_action :authenticate_user! to another controller, and it works fine.
Do I need to do something else to the ApplicationController, to make the login be required on all actions (Except signup/signin)?
Here's the actual code we use:
#app/controllers/application_controller.rb
Class ApplicationController < ActionController::Base
#Actions
before_action :authenticate_user! #-> routes to the login / signup if not authenticated
end
The problem you probably have is two-fold:
--
Make sure your other controllers are inheriting from application_controller:
#app/controllers/other_controller.rb
Class OtherController < ApplicationController
...
end
--
You're somehow "skipping" the before_action callback
If you're using skip_before_action anywhere, you need to remove it. It will likely cause a problem with your authenticate_user! method. To fix this, I would firstly test without any skip_before_action callbacks, and then see what gets it working correctly
A further note - signin / signup won't matter. They all inherit from the Devise controllers; they'll just run as required.
UPDATED 2019
In your routes.rb file you may have mentioned only authenticated_user path like below
authenticated :user do
root to: 'home#index', as: :root_app
end
You should mention unauthenticated_user path too to make it work or just root path without unauthenticated_user or authenticated_user

rails skip_before_filter within method (after other before_filters have been run)

In application_controller.rb I have the following:
before_filter :get_events
before_filter :get_sitemap
def login_required
return true if session[:user]
# If we get to this point, I want to avoid running get_events and get_sitemap
flash[:warning] = 'Please login to continue'
redirect_to login_users_url
return false
end
And in other controllers I have for example:
before_filter :login_required, :except => [:show]
So essentially I have methods running that access the database for all pages except I don't want it to happen when the user is required to log in (i.e., being redirected from a page where normally get_events and get_sitemap are required).
I realize one way of doing this is to run login_required as a before_filter on ALL controllers before any other before_filters are set and then exclude certain controller models but I'd like to know if there's a way of doing it without having to change all my controllers.
For something like this, I usually create an AuthenticatedController (in app/controllers/authenticated_controller.rb):
class AuthenticatedController < ApplicationController
before_filter :require_login
end
Then I derive all controllers requiring authentication from that, specifying a skip_before_filter :require_login for actions I want to exclude on a controller-by-controller basis. For example:
class PlanetsController < AuthenticatedController
skip_before_filter :require_login, only: [:index]
end
This will require you to change all controllers, but only for the purpose of deriving from AuthenticatedController. As far as I know this is a perfectly acceptable way of handling it, and I don't think there's a way outside of monkey patching ActionController::Base to make this apply to all controllers, which is a pretty bad idea for a variety of reasons.
Well after considering Joshua's answer I still couldn't get what I wanted to go for...so what I did was do a little hybrid solution. All controllers still reference ApplicationController, but within ApplicationController I always run the before_filter :login_required FIRST before other before_filters. Redirects in rails seem to stop other before_filters from running, which is what I wanted. In the other controllers I use the skip_before_filter :login_required, :only => [:this_time] wherever necessary.

Skipping authorization for certain methods

Per the Agile Development book, I have an Admin MVC that controls how users log in. In ApplicationController, I have a before_filter that checks for authorization. So, this will check that the user has logged in for every page.
The problem is that I want everyone to be able to access the new method, for example, in Users (that is, anyone should be able to create a new user -- naturally! Only admin users should have access to the other methods in UsersController such as edit, etc.). What's the best way to do that?
You can either of this
before_filter :except=>[:method_name] #methods you want to skip filter
OR
before_filter :only=>[:method_name] #methods you want to be filtered before called.
EDITED
before_filter :filter_method, :except=>[:method_name] #methods you want to skip filter
OR
before_filter :filter_method, :only=>[:method_name] #methods you want to be filtered before called.
You can use the skip_before_filter method in child controller classes to skip the default filter processing. For example:
class UsersController < ApplicationController
skip_before_filter :authorize, :only => [:new, :create]
end
—Will skip the before filter named :authorize only for the new and create actions within the users controller i.e. the filter will still get applied for all other actions.
I would also suggest using CanCan gem for authorization as it has a really simple and clean way to define authorization rules.
http://github.com/ryanb/cancan

Resources