NameError in PagesController#index - ruby-on-rails

I'm trying to create a login system with devise, cancancan and rolify. The devise part is working. I recently added cancancan and rolify and I'm trying to test if they are working.
My cancancan ability file:
class Ability
include CanCan::Ability
def initialize(user)
if user.has_role? :admin
can [:index], Page
else
can [:index,:lecture]
end
end
end
I have a root page root to: "pages#index" which is working. If I add load_and_authorize_resource at the top of the pages controller like
class PagesController < ApplicationController
load_and_authorize_resource
def index
end
def lecture
end
end
I get back when trying to access it:
NameError in PagesController#index generate by these lines:
names.inject(Object) do |constant, name|
if constant == Object
* constant.const_get(name)
else
candidate = constant.const_get(name)
next candidate if constant.const_defined?(name, false)
The * is the line that gives the error. I also saw in the rolify documentation that I have to add resourcify to the files that are going to make use of it. But if I try to add it I get an error undefined method resourcify. How can I solve this ?

Check the following:
GemFile:
gem 'load_and_authorize_resource'
# bundle install after
ApplicationController:
class ApplicationController < ActionController::Base
include LoadAndAuthorizeResource
end
PagesController
class PagesController < ApplicationController
load_and_authorize_resource
....
More Info here Load And Authorize Resource

Related

Facing the NameError when trying to include concerns in my rails 6 controller

I am trying to create a small project for practising the API Key Authentication using the this tutorial. I have created a concern in following directory of the rails project.
app/controllers/concerns/api_key_authenticable.rb
module ApiKeyAuthenticatable
extend ActiveSupport::Concern
include ActionController::HttpAuthentication::Basic::ControllerMethods
include ActionController::HttpAuthentication::Token::ControllerMethods
attr_reader :current_api_key
attr_reader :current_bearer
# Use this to raise an error and automatically respond with a 401 HTTP status
# code when API key authentication fails
def authenticate_with_api_key!
#current_bearer = authenticate_or_request_with_http_token &method(:authenticator)
end
# Use this for optional API key authentication
def authenticate_with_api_key
#current_bearer = authenticate_with_http_token &method(:authenticator)
end
private
attr_writer :current_api_key
attr_writer :current_bearer
def authenticator(http_token, options)
#current_api_key = ApiKey.find_by token: http_token
current_api_key&.bearer
end
end
In my Controller, I am trying to include the concern like this
app/controllers/ApiKeysController.rb
class ApiKeysController < ApplicationController
include ApiKeyAuthenticatable
# Require token authentication for index
prepend_before_action :authenticate_with_api_key!, only: [:index]
# Optional token authentication for logout
prepend_before_action :authenticate_with_api_key, only: [:destroy]
def index
end
def create
end
def destroy
end
end
But when I run the server and visit the index action of the controller, I get the following error
NameError (uninitialized constant ApiKeysController::ApiKeyAuthenticatable):
app/controllers/ApiKeysController.rb:10:in `<class:ApiKeysController>'
app/controllers/ApiKeysController.rb:2:in `<main>'
Can anybody help me out to fix this issue?
Author here. Your concern’s filename is authenticable but your module is authenticatable. You’ll need to correct the typo in the concern filename.

Using Vanity URLs and CanCanCan gem (load_and_authorize_resource error)

I'm attempting to use Vanity URLs in my Rails app so that instead of an ID, the username is shown. I've created the slug so that the username is used in the url instead of the id (everything works here ok), the issue I'm facing occurs when I try to load a page where I have load_and_authorize_resource enabled in the controller. I believe this is attempting to find the user via the id instead of the slug which is causing the error "Couldn't find User with id=X". Is there somewhere I can override the load_and_authorize_resource so that it uses the slug and not the ID?
class User < ActiveRecord::Base
def to_param
slug
end
end
class UsersController < ApplicationController
load_and_authorize_resource only: [:dashBoard]
def dashboard
end
def show
#this is the user's profile page, because I don't have a load
#and authorize resource check on it, it loads without error
#when the vanity url is enabled
#user = User.find_by_slug(params[:id])
end
end
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.memberships.count > 0
can :manage, User
else
can :read, :all
end
end
end
I figured it out; adding find_by: :slug to the load_and_authorize_resource did exactly what I was looking for.
load_and_authorize_resource only: [:dashBoard], find_by: :slug

Pundit Headless Policy

I'm using pundit for access control in the admin section of my app. I have a dashboards controller that looks like this:
class Admin::DashboardsController < AdminController
def index
#total_revenue = Order.total_revenue
authorize :dashboards, :index?
end
...
end
and a policy that looks like this:
class DashboardPolicy < Struct.new(:user, :dashboard)
def index?
true
end
end
When I try to access /admin/dashboards/ I get a Pundit::NotDefinedError, unable to find policy SymbolPolicy for dashboards
I've also tried namespacing the policy and got the same error.
jizak's answer did not work for me, I found following solution for headless name-spaced policies, the trick being with the [:admin, :policy] first argument.
class Admin::HomeController < AdminController
def dashboard
authorize [:admin, :home], :dashboard?
end
end
And then for the policy:
Admin::HomePolicy < AdminPolicy
def dashboard?
return false unless user && user.admin?
true
end
end
I have such headless policy:
app/policies/admin/statistic_policy.rb
class Admin::StatisticPolicy < Struct.new(:user, :statistic)
def show?
user.admin?
end
end
app/controllers/admin/statistics_controller.rb
class Admin::StatisticsController < Admin::ApplicationController
def show
per_today Time.zone.now
authorize :statistics, :show?
end
...
end
and it works for me.
Try to update gem, because these changes are new (https://github.com/elabs/pundit/issues/77).
Delete your Gemfile.lock from the project and do 'bundle install'.
I recently had the same issue. The problem that I faced was that the controller was without a model.
Remember that Pundit is a model based authorization, not so much of controller based.
Before creating an Admin class (in the models), I was getting the same error as you were. Also, take note of the authorization statement on my dashboard action in the controller.
controllers/admin_controller.rb
class AdminController < ApplicationController
after_action :verify_authorized
def dashboard
authorize Admin, :dashboard?
end
end
models/admin.rb
class Admin
def self.policy_class
AdminPolicy
end
end
policies/admin_policy
class AdminPolicy < Struct.new(:user, :admin)
def dashboard?
user.admin?
end
end
I managed to use Pundit on namespaced controller actions regardless of the model by using this:
In my /private/scrapers_controller.rb I have
module Private
class ScrapersController < Private::PrivateApplicationController
# Pundit authorizations
before_action { authorize [:private, :scrapers] }
def index
end
...
And then in policies/private/scrapers_policy.rb
class Private::ScrapersPolicy < ApplicationPolicy
def index?
return true if user.has_role?(:super_admin)
return false
end
end
This will disallow visiting scrapers#index or any other action within the controller to any user who's not an :super_admin
To disallow only index explicitly you can use:
before_action { authorize [:private, :scrapers], :index? }
Check yout pundit version. You may need to run 'bundle update pundit', because headless policies were merged to master quite recently and before that you had need to install pundit from github: 'elabs/pundit' to use them.
Described issue
Merged headless policies
if you just want to render landing page for controller dashboard#index for example, where no need to authorize users you can just skip authorization like
dashboard_controller.rb
class DashboardController < ApplicationController
def index
skip_policy_scope
end
end
And therefore you don't have to create DashboardPolicy at all.

uninitialized constant of controller

Hi i am trying to use cancan but I have very irritating error, namely: uninitialized constant Edition
for controller :
class EditionsController < ApplicationController
before_filter :authenticate_user! #devise
load_and_authorize_resource
def index
end
end
with this route:
get "editions/index"
and such abilities:
user ||= User.new # guest user (not logged in)
if user.has_role? "admin"
can :manage, Edition
cannot :commission
else
can :read, :commission
end
And additional question, how i can create cancan ability for singular(name) controller ?
for example PhotoController
The problem is that you are using a custom class.
CanCan tries to singularize the controller class name to match the model class name and that sometimes isn't what we expect:
...
If the model class is namespaced differently than the controller you will need to specify the :class option.
source: https://github.com/ryanb/cancan/wiki/authorizing-controller-actions
In my case, I had a class with no model, so I just added ":class => false" at the end of the command:
load_and_authorize_resource :class => false
If you have load_and_authorize_resource defined in the ApplicationController and want to override it only for this controller:
class EditionsController < ApplicationController
skip_load_and_authorize_resource
def index
#editions = Edition.accessible_by(current_ability).order(:date)
end
end

CanCan - Undefined method find for specific class

I have a controller named Administrator. This controller has actions to anothers models. When I try to authorize this actions with CanCan I get this response.
<h1>
NoMethodError
in AdministratorController#preproduct_delete
</h1>
<pre>undefined method `find' for Administrator:Class</pre>
The controller code begins with:
class AdministratorController < ApplicationController
load_and_authorize_resource
before_filter :authenticate_user!
def users
authorize! :users, "Users List"
#users = User.all
end
end
The ability model has:
if user.admin? then :admin
can :users
end
The authenticate_user! method:
# See ControllerAdditions#authorize! for documentation.
def authorize!(action, subject, *args)
message = nil
if args.last.kind_of?(Hash) && args.last.has_key?(:message)
message = args.pop[:message]
end
if cannot?(action, subject, *args)
message ||= unauthorized_message(action, subject)
raise AccessDenied.new(message, action, subject)
end
subject
end
I tried to remove load_and_authorize_resource from the controller, but when any action is called, CanCan redirects me to login page every time.
Thanks a lot
You did not specified the permission, what does can :user mean ? specify a permission, for all permissions use :manage.
if user.admin?
can :manage, :users
end
<h1>
NoMethodError
in AdministratorController#preproduct_delete
</h1>
Please paste preproduct_delete of AdministratorController
<pre>undefined method `find' for Administrator:Class</pre>
Is Administrator inheriting from ActiveRecord::Base ? if it doesn't have find is because is not.
it should be
class Administrator < ActiveRecord::Base
The authenticate_user! method:
# See ControllerAdditions#authorize! for documentation.
def authorize!(action, subject, *args)
....
end
THIS IS NOT the authenticate_user! method, this is authorize! very different, you have before_filter authenticate_user! post this method here. Something is calling preproduct_delete.
One possible reason is that the class name needs to be explicitly set. In my example I had the comments resource nested under the thread resource, and I was writing the following in controller:
class Buy::CommentsController < ApplicationController
load_and_authorize_resource :thread
This gives me undefined find method error, because comment model was under the thread namespace. When I explicitly set it like the following it works.
class Buy::CommentsController < ApplicationController
load_and_authorize_resource :thread, class: Buy::Thread

Resources