I have an engine called Admin and a few controllers.
# admin/app/controllers/admin/application_controller.rb
module Admin
class ApplicationController < ActionController::Base
end
end
# admin/app/controllers/admin/foo_controller.rb
module Admin
class CardsController < ApplicationController
end
end
# app/controllers/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
end
If I visit my main app and THEN /admin the CardsController inherits from ApplicationController NOT Admin::ApplicationController. If I first visit /admin and then the main app it works.
I guess that when we first visit the main app the constant ApplicationController is created, which is then found and used when visiting /admin instead of loading Admin::ApplicationController.
How can one avoid this issue?
You'll have to be specific about which class you are inheriting from:
module Admin
class CardsController < Admin::ApplicationController
# ...
end
end
Related
I am using existing rails application, where we currently use devise for authentication and Pundit for authorization. My requirement is to skip all policies scope authorization for all action in this existing rails application. How Can I do this?
I have tried below code but not worked:-
class ApplicationController < ActionController::Base
include Pundit
protect_from_forgery with: :exception
before_action :authenticate_user!, :set_default_timezone#, :modify_search_params
before_action :set_current_user
skip_after_action :verify_policy_scoped
#.....
end
Thanks in advance :)
Pundit provides skip_authorization to skip his authorization. Executing it before all actions of the controller will make it work for your requirement.
class ApplicationController < ActionController::Base
# ...
before_action :skip_all_authorization
private
def skip_all_authorization
skip_authorization
end
# ...
end
You need to skip both action authorization with an object (which are called by using authorize(object) and with a policy scope (called with policy_scope).
You can skip the hooks on your base class:
skip_after_action :verify_policy_scoped
skip_after_action :verify_authorized
Or just add another hook to skip them on your controller (my preferred approach)
after_action :skip_all_authorization
private
def skip_all_authorization
skip_policy_scope
skip_authorization
end
But by the way, you shouldn't need this unless you're ensuring the policy is called by adding the appropriate hooks.
I've built a Shopify app on Rails using shopify_app gem. I want to call a method immediately after a store owner installs the app, but I'm having trouble figuring out where I would call that.
What is the controller#action when a new instance of the app is created?
I have
class ApplicationController < ActionController::Base
include ShopifyApp::Controller
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
class AuthenticatedController < ApplicationController
before_action :login_again_if_different_shop
around_filter :shopify_session
layout ShopifyApp.configuration.embedded_app? ? 'embedded_app' : 'application'
end
class HomeController < AuthenticatedController
def index
#customers = ShopifyAPI::Customer.find(:all, :params => {:limit => 100})
end
end
class SessionsController < ApplicationController
include ShopifyApp::SessionsController
end
I am learning to use Pundit for authorization. But the way I see it is authorization for resources not pages. I want a user to be redirected to a unauthorized page if he/she is not authorized to visit the page using pundit.
For e.g.
class OnlyAdminCanVisitController < ApplicationController
before_filter :admin_authenticate
Stops a non-admin role user.
Also, I want to take care of made up scenarios like following(Considering there are 4 roles as Admin,Manager,Employee,Outsider. The design below is obiviously bad)
class AdminManagerCanVisitController < ApplicationController
before_filter :admin_or_manager_authenticate
class AdminEmployeeCanVisitController < ApplicationController
before_filter :admin_or_employee_authenticate
class AdminOutsiderCanVisitController < ApplicationController
before_filter :admin_or_outsider_authenticate
class AdminManagerEmployeeCanVisitController < ApplicationController
before_filter :admin_or_manager_employee_authenticate
I have 4 roles and would like to write pundit policies for these controllers which allows any combination of authorizations.
Let me know if pundit is designed to tackle this issue.
Thanks
There is not much difference between pages and resources actually. So you can solve your problem by rescuing a denied Authorization from your application_controller.rb :
class ApplicationController < ActionController::Base
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
protected
def admin_authenticate
authorize current_user, :admin?
end
private
def user_not_authorized(exception)
# Redirect to whatever page you want if not authorized
end
end
You then need to define your policy. I generally create an admin? method in application_policy.rb (https://github.com/elabs/pundit#policies) so it is spread on my other policies as well :
class ApplicationPolicy
def admin?
# Logic to ensure the user is an admin
end
end
class UserPolicy < ApplicationPolicy
end
Then in your other controllers, just do as you did :
class OnlyAdminCanVisitController < ApplicationController
before_action :admin_authenticate
end
I am setting up a very simple rails app that involves a simple authentication check before you can enter the site. But, when the before_filter runs, and the user is redirected to the login path, a redirect loop occurs.
ApplicationController:
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 :check_session
private
def check_session
redirect_to login_path and return unless current_user?
end
def current_user?
!session[:username].blank?
end
end
SessionsController
class SessionsController < ApplicationController
def new
end
end
The issue is that, since your SessionsController inherits from ApplicationController, it actually inherits the before_filter as well. This means you are not allowing someone to see the login page unless they are logged in, which is usually undesirable behavior. You want to skip this before_filter on the login page:
class SessionsController < ApplicationController
skip_before_filter :check_session, only: :new
def new
end
end
I think you have problem in your routes. One way of solution is defining a root path for your app as:
root 'app_entry#index'
Then create a controller for it as given below:
class AppEntryController < ApplicationController
def index
if current_user
redirect_to 'controller_name/action_name'
else
redirect_to '/users/sign_in'
end
end
Hope this helps you.
You should use the before filter like this
before_filter :check_session, :except => [:new]
I am trying to set the following up:
www.domain.com goes to the main site (user can register, information about application)
foo.domain.com goes to the main application that is customized to the user(subdomain)
what is the best way to separate the rails parts? Namespaced controllers seem frowned upon.
Don't separate them. Just use a before_filter to require login and a subdomain on the controllers that requires a subdomain/client to be present.
class ApplicationController < ActionController::Base
private
def require_subdomain_scope
# check if request.subdomains is blank or www. Something like that.
end
end
class StaticPagesController < ApplicationController
# no before_filter!
end
class ProjectsController < ApplicationController
before_filter :require_login, :require_subdomain_scope
end