Cancan authorize custom module - ruby-on-rails

I have a custom module in my lib directory that I load in my Application controller. I started using cancan and now I am getting Access Denied error for all the actions in my custom module. I don't want cancan to check authorization on my custom module. One way to get around this is to use except => [:action_name_in_my_custom_module] but I have lot of actions that I use in my application at many places. I need a better solution.

Assuming you have a module of controller actions and you are including it in your controllers, is there a reason you didn't put them all in ApplicationController?
One thing you can try is using skip_before_filter in the module. This will call the method on any class in which you include MyModule:
module MyModule
def self.included(klass)
klass.class_eval <<-filters
skip_before_filter :filter_method_to_skip, only: [:method_a, :method_b, ...]
filters
end
end
class MyController < ApplicationController
before_filter :filter_method
include MyModule
end
I believe it needs to be included after your before filters are defined.

Related

creating a controller same as application controller

In my rails application, my application controller becoming bulky with definitions which are used by other controllers.Is there a way to create a controller same as application controller so the same methods can be moved into the new controller and can be accessed by other controller.like Globally define the method or something.
Create concern for overcoming this problem
create one CommonMethods concern under controllers/concerns/common_methods.rb
/concerns/common_methods.rb
# frozen_string_literal: true
module CommonMethods
extend ActiveSupport::Concern
included do
# include your filters here like before_action
end
# write all common methods of application controller here
end
In the ApplicationController include that concern
class ApplicationController < ActionController::Base
include CommonMethods
...
...
end

Create an "includable" Rails controller action within helper

Is it possible to make an includable controller action within a Rails Helper through an included block? I'm thinking something like this:
module XablauHelper
included do
def my_shared_action
true
end
end
end
Already tried doing it through class.eval block and through using like a class method i.e. self.my_shared_action but no success, I have already found a solution that is making a parent controller with the desired shared actions and inheriting from it, but for the sake of modular design I would like to make it a more "global" approach, so I could gemify my solution and reuse code, any suggestions that doesn't use inheritance?
Adding controller actions in a helper is probably the wrong choice, as these methods are intended for your views.
Consider using controller concerns instead, and including them where required. For example:
# in app/controllers/concerns/useful_functions_concern.rb
module UsefulFunctionsConcern
extend ActiveSupport::Concern
included do
rescue_from SomeException, with: :handle_access_denied
end
def useful_method
# ...
end
protected
def handle_access_denied
# ...
end
end
# in your controller
class XyzController < ApplicationController
include UsefulFunctionsConcern
def index
useful_method
end
end
Where common controller actions can be shared and the controllers have something in common e.g. they are all API controllers, also consider using inheritance to achieve this. For example:
# parent controller
class ApiController < ApplicationController
def my_shared_action
end
end
class SpecificApiController < ApiController
end

Where to put Ruby helper methods for Rails controllers?

I have some Ruby methods certain (or all) controllers need. I tried putting them in /app/helpers/application_helper.rb. I've used that for methods to be used in views. But controllers don't see those methods. Is there another place I should put them or do I need to access those helper methods differently?
Using latest stable Rails.
You should define the method inside ApplicationController.
For Rails 4 onwards, concerns are the way to go. There was a decent article which can still be viewed via the Wayback Machine.
In essence, if you look in your controllers folder you should see a concerns sub-folder. Create a module in there along these lines
module EventsHelper
def do_something
end
end
Then, in the controller just include it
class BadgeController < ApplicationController
include EventsHelper
...
end
you should define methods inside application controller, if you have few methods then you can do as follow
class ApplicationController < ActionController::Base
helper_method :first_method
helper_method :second_method
def first_method
... #your code
end
def second_method
... #your code
end
end
You can also include helper files as follow
class YourController < ApplicationController
include OneHelper
include TwoHelper
end
You can call any helper methods from a controller using the view_context, e.g.
view_context.my_helper_method
Ryan Bigg response is good.
Other possible solution is add helpers to your controller:
class YourController < ApplicationController
include OneHelper
include TwoHelper
end
Best Regards!
Including helpers in controller will end-up exposing helper methods as actions!
# With new rails (>= 5)
helpers.my_helper_method
# For console
helper.my_helper_method

CanCan: load_and_authorize_resource in namespace other than that of MainApp

I'm using CanCan for permissions in my Rails application in which I have built my own engine for some generic form functionality. I would like to lock down permissions in my system so that users cannot freely access my engine controllers' actions. These controllers, for the most part, just make use of the 7 REST actions, so I would like to use CanCan's load_and_authorize_resource at the top of each controller.
However, when I write my code like this:
module MyEngine
class FormController < ApplicationController
load_and_authorize_resource
...
end
end
I get this error:
uninitialized constant Form
My guess is that the automatic loader in load_and_authorize_resource is tied to my MainApp namespace, and does not recognize that I am calling it in a different namespace, and so does a call like Form.find(params[:id]) rather than MyEngine::Form.find(params[:id]).
If this is the case, how can I fix this? It's not a huge deal because authorize! still works properly, so I can define the authorization in each action individually, but it would feel much cleaner if I were able to use the load_and_authorize_resource method.
CanCan can not find namespaced models. Try to specify class:
load_and_authorize_resource class: MyEngine::Form
It seems to be a bug in CanCan::ControllerResource#namespace:
def namespace
#params[:controller].split("::")[0..-2]
end
As you see, it tries to split controller path by :: but it comes in the form of my_engine/my_controller.
So the fix is dumb simple:
def namespace
#params[:controller].split("/")[0..-2]
end
Wonder how they could miss such a stupid bug for so long. Shall send them a pull request.
P.S. Have just signed up to answer 8)
If the model class is namespaced differently than the controller, you will need to specify the :class option.
module MyEngine
class FormController < ApplicationController
load_and_authorize_resource :class => MyEngine::Form
...
end
end

Calling a method from another controller

If I've got a method in a different controller to the one I'm writing in, and I want to call that method, is it possible, or should I consider moving that method to a helper?
You could technically create an instance of the other controller and call methods on that, but it is tedious, error prone and highly not recommended.
If that function is common to both controllers, you should probably have it in ApplicationController or another superclass controller of your creation.
class ApplicationController < ActionController::Base
def common_to_all_controllers
# some code
end
end
class SuperController < ApplicationController
def common_to_some_controllers
# some other code
end
end
class MyController < SuperController
# has access to common_to_all_controllers and common_to_some_controllers
end
class MyOtherController < ApplicationController
# has access to common_to_all_controllers only
end
Yet another way to do it as jimworm suggested, is to use a module for the common functionality.
# lib/common_stuff.rb
module CommonStuff
def common_thing
# code
end
end
# app/controllers/my_controller.rb
require 'common_stuff'
class MyController < ApplicationController
include CommonStuff
# has access to common_thing
end
Try and progressively move you methods to your models, if they don't apply to a model then a helper and if it still needs to be accessed elsewhere put in the ApplicationController
If you requirement has to Do with some DB operations, then you can write a common function (class method) inside that Model. Functions defined inside model are accessible across to all the controllers. But this solution does to apply to all cases.
I don't know any details of your problem, but maybe paths could be solution in your case (especially if its RESTful action).
http://guides.rubyonrails.org/routing.html#path-and-url-helpers

Resources