Undefined method error for displaying in JSON - ruby-on-rails

I'm writing a simple Ruby API for a to-do list. Here is what I have so far:
API CONTROLLER:
class ApiController < ApplicationController
skip_before_action :verify_authenticity_token
private
def authenticated?
authenticate_or_request_with_http_basic {|username, password| User.where( username: username, password: password).present? }
end
end
API/USERS_CONTROLLER:
class Api::UsersController < ApplicationController
before_action :authenticated?
def index
users = User.all
render json: users, each_serializer: UserSerializer
end
end
ROUTES:
Rails.application.routes.draw do
namespace :api, defaults: { format: :json } do
resources :users
end
resources :welcome, only: [:index]
root 'welcome#index'
end
When I try to navigate to the api_users_path, it brings up the error:
undefined method `authenticated?' for # Api::UsersController:0x007f36a3f779f8
I'm sure there is something simple I am missing, can someone point me in the right direction?

To make the authenticated? method available to your Api::UsersController, change private to protected in application_controller.rb:
class ApiController < ApplicationController
skip_before_action :verify_authenticity_token
protected
def authenticated?
authenticate_or_request_with_http_basic {|username, password| User.where( username: username, password: password).present? }
end
end
Changing to protected will make that method available to ApplicationController and all of it's sub-classes. If it's set to private that method will only be available to ApplicationController itself.
You should also make sure that Api::UsersController inherits from ApiController:
class Api::UsersController < ApiController
...
end

The method authenticated? is defined on ApiController. Api::UsersController does not have access to this method. To use it on all your controllers you can define this method on ApplicationController as protected.

Related

Rails 5, pundit authorization

Pundit works well, if action has resources like:
class Admin::PagesController << ApplicationController
def index
#pages = Page.all
end
end
How to authorise method without any resources in action?
class Admin::DashboardController << ApplicationController
def index
end
end
I hav file policies/admin/dashboard_policy.rb
class Admin::DashboardPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.all
end
end
end
This file was generated by command:
rails g pundit:policy Admin/Dashboard
File views/admin/index.html.slim has only static text. Nothing more.
How to authorise action without any resources?
Regards
Sssebaaa
To authorize without a scope or model instance call authorize with a symbol or array of symbols (when namespaced):
class Admin::DashboardController << ApplicationController
def index
authorize [:admin, :dashboard]
end
end
This will call the #index? method on the policy class:
class Admin::DashboardPolicy < ApplicationPolicy
def index?
user.admin?
end
end
You can also remove the scope completely from your policy.
If you don't have any callbacks checking that the policy is scoped, as pundit doc suggests, like
class ApplictationController < ActionController::Base
include Pundit
after_action :verify_policy_scoped, only: :index
end
You don't have anything to do.
However if you do have a callback, you can just skip it in your controller action like this:
class Admin::DashboardController << ApplicationController
skip_after_action :verify_policy_scoped, only: [:index]
def index
end
end

Check if current request is protected in Rails with CanCan

I'm using the CanCan gem in my Rails app and want to check if the current request is a protected resource in my application.
So for example I have the following:
class AdminController < ApplicationController
load_and_authorize_resource
end
How can I check if the request is protected by CanCan?
I can access the controller and action via params. I can't use the standard can? and cannot? helpers as they will check if the current_user has permission rather than if the action itself has a protection on it.
So for example:
class ApplicationController < ActionController::Base
before_action :check_protected
def check_protected
if can? params[:action].to_sym, Object.const_get(params[:controller].classify)
# resource is protected
else
# resource is not protected
end
end
end
^^ This won't work because it will always say false when no current_user or if the user doesn't have permission. I need to check if the resource itself is protected with CanCan.
If I had these examples:
class PostsController < AdminController
def index
end
end
class HomeController < ApplicationController
def index
end
end
The index for PostsController should be identifiable as protected, and the index for HomeController as unprotected.
CanCan uses CanCan::ControllerResource#skip? method to determine whether it should authorize resource or not. So I guess you may rely on it as follows:
def check_protected
if CanCan::ControllerResource.new(self).skip?(:authorize)
# resource is not protected
else
# resource is protected
end
end
I've tried it in my sandbox and it worked for me

Ruby on Rails' skip_before_action doesn't work as expected

There are 2 namespaces:
api/public
api/mobile
Doorkeeper authorization with proper scope is created in public controller. For example:
class API::Public::PostsController < ApplicationController
before_action -> { doorkeeper_authorize! :public }
def show
#post = Post.find(params[:id])
end
end
Controller in mobile namespace is inherited from controller in public namespace. For example:
class API::Mobile::PostsController < API::Public::PostsController
skip_before_action :doorkeeper_authorize!
before_action -> { doorkeeper_authorize! :mobile }
end
So the point here is that functionality is same and if there is some difference for mobile then action could be overridden in mobile namespace.
Problem is that scopes are different for those 2 namespaces, but skipping doorkeeper_authorize! doesn't work.
Is there a way to solve this?
skip_before_filter works for skipping methods, not skipping lambdas/procs. Try creating a method for the public authorization:
class API::Public::PostsController < ApplicationController
before_action :authorize_public
...
def authorize_public
doorkeeper_authorize! :public
end
end
class API::Mobile::PostsController < API::Public::PostsController
skip_before_action :authorize_public
...
end
You could call a method within your lambda that returns what to authorize:
class API::Public::PostsController < ApplicationController
before_action -> { doorkeeper_authorize! authorization_scope }
def show
#post = Post.find(params[:id])
end
protected
def authorization_scope
:public
end
end
Then your subclasses only need to override the method without getting into a skip_before_filter pain
class API::Mobile::PostsController < API::Public::PostsController
protected
def authorization_scope
:mobile
end
end

How to get the name of the action in an after_action filter for ActionMailer

In the class below, how do I get the current action name (i.e. email_confirmation, password_reset) in side the after_action callback add_mandril_headers?
class UserMailer < ActionMailer::Base
after_action :add_mandril_headers
def email_confirmation(user)
mail(..)
end
def password_reset(user)
mail(..)
end
private
# how to get the action name?
def add_mandrill_headers
headers['X-MC-Tags'] = [mailer_name, action_name].join('_');
end
end
Turns out action_name returns the current mailer action name. I tried it based on the fact that ActionController has a similar method.
Thanks #HarishShetty!
As you mentioned, the action_name is good for all Controllers, as it is inherited from ApplicationController.
For example, I was using public_activity and wanted some simplification in my controllers:
class SiteDetailsController < ApplicationController
after_action :track_activity, only: [:create, :update, :destroy]
# ...
private
def track_activity
#site_detail.create_activity action_name, owner: current_user
end
end

How to exclude a single controller action from a filter in Rails 3.07?

class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :check_session_expiry, :except => :login
How do you exclude a single controller's (the users controller, for example) login action?
First, I'm not on a machine with rails to test it, but the following should work:
class UserController < ApplicationController
skip_filter :check_session_expiry, :only => :foo
# following is DEPRECATED as far as I know
#skip_before_filter :check_session_expiry, :only => :foo
def foo
end
end
class ApplicationController < ActionController::Base
before_filter :check_session_expiry
def check_session_expiry
return true if self.class != UsersController && self.action == "login"
# do your thing
end
I would just redefine check_session_expiry in your controller to be an empty method.
class UserController < ...
...
private
def check_session_expire
# optional if other actions shall still use the filter
super unless self.action == 'login'
end
end

Resources