I'm not sure what is the best way to make sure that every user has some necessary attributes, and if they don't i would like to redirect them to 'new' page e.g.
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :authenticate_user!, :valid_location
def valid_location
if (current_user.location.nil? || current_user.location.city.nil?)
redirect_to new_user_locations_path(current_user.id)
else
true
end
end
The above example is flawed because it creates a redirect loop. I could definetelly use some advice on creating this sort of validation. Thank you
The reason why this is creating a redirect loop is because the valid_location method is also being called on the controller responsible for the new_user_locations_path. To prevent this you need to make sure that controller does not run that filter with skip_before_filter (skip_before_action in Rails 4). A similar issue has been answered here.
class LocationsController < ApplicationController
skip_before_filter :valid_location, only: [:new, :create]
#...
end
Because valid_location returns a true/false boolean, I would recommend renaming the method to valid_location? or invalid_location? and refactoring the logic a little:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :authenticate_user!, :redirect_invalid_locations
private
def redirect_invalid_locations
redirect_to(new_user_locations_path(current_user)) if invalid_location?
end
def invalid_location?
current_user.try(:location).try(:city).nil?
end
end
class LocationsController < ApplicationController
skip_before_filter :redirect_invalid_locations, only: [:new, :create]
end
Related
So I have a controller, say
class RandomActionController < ApplicationController
and I have a method check_authorization in ApplicationController that I use in RandomActionController as
before_action :check_authorization, except: [:create, :get_actions, ..]
Now in another action inside RandomActionController, I might be building an array of actions excluding ones in the except section of check_authorization, or whatever. My problem is, how do I get those actions as a hash/array or any other form?
What you are passing to the except part is a literal array, string or symbol. Rails does not let you (afaik) introspect a controller callback to extract the arguments it was declared with.
If you want to be able to a re-use list of actions it you need to link it to an identifier.
For example this a pattern I often use:
class ApplicationController
private
def self.member_actions
[:show, :edit, :destroy, :update]
end
def self.collection_actions
[:new, :index, :create]
end
end
class FooController < ApplicationController
before_action :set_foo, only: member_actions
def self.member_actions
super + [:fuzzle, :wuzzle]
end
end
But you can just as well use constants or anything else that is available in the class context.
In order do add security in devise, i need to set the "before_filter" thingy, like:
before_filter :authenticate_student!, only: [:new, :edit]
which is great... But my app need two user types... students and teachers. How do i make the controller just check if any of then is authenticate?
like:
before_filter :authenticate_any!, only: [:new, :edit]
How can i archive that?
I am using Ruby 2.2.0, and rails 4.
Just define those methods in your application controller
class ApplicationController < ActionController::Base
def authenticate_student!
authenticate_user! && current_user.student?
end
def authenticate_any!
authenticate_user!
end
end
You may complete the code of how to check student?
I have a rails 4.2.x app, with devise for authentication - I have several controllers.
I want the devise authenticate_user! method to be run on all controllers and actions except on the home controller index action. (Of course, authenticate_user! itself takes care that devise actions like login go through)
I can ensure that every controller action runs the before_action in application_controller.rb:
class ApplicationController < ActionController::Base
before_action :authenticate_user!
...
end
I can also restrict a specific set of actions on all controllers:
class ApplicationController < ActionController::Base
before_action :authenticate_user!, except: [:index]
...
end
But I don't see how to make just home/index to be an exception.
I could, of course, manually add before_action :authenticate_user! to every controller, and add an exception to the home controller for the index action. But this is not very dry, and if I add new controllers, I need to remember to add this before_action to each of them.
What you have to do is to set autheticate_user! on all controllers like that :
class ApplicationController < ActionController::Base
before_action :authenticate_user!
...
end
And then on your HomeController you do that :
class HomeController < ApplicationController
skip_before_action :authenticate_user!, only: [:index]
...
end
Hope this will help you !
You can use params[:controller] to detect controller name of request.
class ApplicationController < ActionController::Base
before_action :authenticate_user!
AUTHENTICATE_USER_EXCEPT_CONTROLLERS = ['controller_names_you_want_to_exclude']
...
def authenticate_user!
unless AUTHENTICATE_USER_EXCEPT_CONTROLLERS.include?(params[:controller])
super
end
end
end
I have installed devise gem for authentication. I have created a scaffold named Members. I have put
before_filter :authenticate_user!
at the top of the Members controller. but I want to make
Member.Show
action to be out of the authentication. I mean with out signing in any one can see the Members profile.
Thanks
You can add this line in your controller (typically, at the beginning):
class MembersController < YourBaseController
# ...
skip_before_filter :authenticate_user!, only: [:show]
# ...
end
The most elegant way is to use an except filter for this:
class MembersController
...
before_filter :authenticate_user!, except: :show
..
end
This way all of your logic around the filter is contained in one place. You can also pass in an array of actions to exclude:
class MembersController
...
before_filter :authenticate_user!, except: [:show, :another_action]
..
end
For more see: http://apidock.com/rails/ActionController/Filters/ClassMethods/before_filter
You can simply do
class MembersController < ApplicationController
skip_before_filter :authenticate_user!, only: [:show]
#rest of the codes
def show
#show codes
end
end
My application controller looks like this
class ApplicationController < ActionController::Base
include AuthenticatedSystem
helper :all # include all helpers, all the time
protect_from_forgery # :secret => 'sup3rs3cr3t'
filter_parameter_logging :password
# Here's the interesting bit
before_filter :login_required, :except => [:index, :show, :new]
end
Now I have another controller that looks like this
class CompletelySecretController < ApplicationController
# the other interesting bit
before_filter :login_required
def index
#secrets = Secret.find(:all)
end
end
I can still see all of the secrets, despite me stating that a login is required for all actions with
before_filter :login_required
Is it not intuitive to think that the before_filter in the child class overrides the before_filter in the parent class?
before_filter in your subclass doesn't override the same call in the super class, but they stack after each other instead. It is how the chain of filters work. If you want to skip the filter added in your ApplicationController, you can use skip_before_filter method - see "Filter Chain Skipping" section here in the filters documentation.