How do I test this with rspec? - ruby-on-rails

I'm using the Sorcery gem for user signup/login.
One feature of this gem is the require_login before_filter on any controller you want to authenticate.
I have created a dashboard namespace for my app after they've logged in. For example /dashboard/reports or /dashboard/employees, etc.
Routes file:
# Dashboard
namespace :dashboard do
# Recent Activity
get '' => redirect('/dashboard/recent-activity')
get 'recent-activity' => 'activities#index', :as => 'root'
# Other dashboard controllers and actions
end
I extracted out the before_filter into it's own controller called:
"app/controllers/dashboard/base_controller.rb"
class Dashboard::BaseController < ApplicationController
before_filter :require_login
end
What I'd like to do is make 100% sure in some kind of test that ANY new controller I create within the dashboard folder (or dashboard namespace), inherits from Dashboard::BaseController
Such as my activities controller for example:
class Dashboard::ActivitiesController < Dashboard::BaseController
I dont want to go creating controllers in a few months and accidentally make it inherit from ApplicationController which would still would but wouldnt have login functionality.
I'm using RSpec

Can't quite believe my own eyes that I solved this on my own....
require 'spec_helper'
describe Dashboard::BaseController do
it "is the superclass of every dashboard namespaced controller" do
Rails.application.eager_load!
ApplicationController.descendants.each do |controller|
if controller.to_s.include?("Dashboard::") && controller.to_s != "Dashboard::BaseController"
expect(controller.superclass.to_s).to eq("Dashboard::BaseController")
end
end
end
end

Related

CanCan authorize all controllers

I have CanCan and Rolify set up with ActiveAdmin, and now it's time to force authorization on my controllers.
Do I have to authorize_resource on every controller (We have a couple dozen models and controllers now), or is there a way to apply it to all of my ActiveAdmin controllers?
I tried calling it in a before_filter from ActiveAdmin.setup, but that didn't work.
I made an initializer: config/initializers/active_admin-cancan.rb
module ActiveAdmin
class ResourceController
# If you don't skip loading on #index you will get the exception:
#
# "Collection is not a paginated scope. Set collection.page(params[:page]).per(10) before calling :paginated_collection."
load_resource :except => :index
authorize_resource
def scoped_collection
end_of_association_chain.accessible_by(current_ability)
end
end
end
Borrowed from another user's code, but now I can't find the source any more.

How to skip application_controller calls only when within a certain namespace (ActiveAdmin)

I am attempting to use active admin with a project. This project also uses another gem to separate out different tenants, as well as has_secure_password for normal authentication.
I am having an issue skipping both of these filters when the user goes to active admin (just a different namespace - admin).
class ApplicationController < ActionController::Base
force_ssl
helper :all
protect_from_forgery
set_current_tenant_by_subdomain(:account, :subdomain) # need to skip this call when in the admin namespace
before_filter :require_user # need to skip this call when in the admin namespace
end
Thanks for your help!
You could create a BaseController that includes set_current_tenant_by_subdomain and before_filter :require_user and have your non-admin controllers inherit from that, while your admin controller inherits directly from the ApplicationController. That's worked for me in the past.
in config/initializers/active_admin.rb you can add the line:
config.skip_before_filter :offending_filter
sadly this does everything except the dashboard controller... for that you need
controller do
skip_before_filter :offending_filter
end
in app/admin/dashboard.rb

How to test application controller before filter methods in Rails 3?

I have a before_filter on my ApplicationController class and I want to write a test for it? Where should I write this test into? I do not want to go into every subclass controller test file and repeat the test about this filter.
Hence, what is the recommended way to test ApplicationController before_filters?
Note that I am using Rails 3.2.1 with minitest.
My case is slightly different than yours, but I needed to do something similar to test authentication across the site (with Devise). Here's how I did it:
# application_controller.rb
class ApplicationController < ActionController::Base
before_filter :authenticate_user!
end
# application_controller_test.rb
require 'test_helper'
class TestableController < ApplicationController
def show
render :text => 'rendered content here', :status => 200
end
end
class ApplicationControllerTest < ActionController::TestCase
tests TestableController
context "anonymous user" do
setup do
get :show
end
should redirect_to '/users/sign_in'
end
end
If there's specific controllers that need to skip the before filter I'll have a test to make sure they skip it in the specific controller's tests. This isn't quite your situation as I'm interested in the effect of the method, not just knowing it was invoked, but I thought I'd share in case you found it useful.
Improving on #bmaddy answser, you do need to setup routing for the specs to run.
Here is a rails 5 working example:
require 'test_helper'
class BaseController < ApplicationController
def index
render nothing: true
end
end
class BaseControllerTest < ActionDispatch::IntegrationTest
test 'redirects if user is not logedin' do
Rails.application.routes.draw do
get 'base' => 'base#index'
end
get '/base'
assert_equal 302, status
assert_redirected_to 'http://somewhere.com'
Rails.application.routes_reloader.reload!
end
test 'returns success if user is loggedin' do
Rails.application.routes.draw do
get 'base' => 'base#index'
end
mock_auth!
get '/base'
assert_equal 200, status
Rails.application.routes_reloader.reload!
end
end
I now believe that I have to have all my controllers tests test about the before_filter existence and that this filter works as expected. This is because, I cannot know whether a controller uses a skip_before_filter when it shouldn't.
Hence, I decided to use mock (#controller.expects(:before_filter_method)) to make sure that the filter is called. So, for example, in a index action I write in my test:
test "get index calls the before filter method" do
#controller.expects(:before_filter_method)
# fire
get :index
end
This will make sure that my controller calls before_filter_method on the particular action. I have to do this on all my actions tests.
If anyone else has a better solution, let me know.
Usually when I want something like this I just test the expected behaviour without taking into account that this particular behaviour may be implemented in a filter and not in a method per se. So for the following simple scenario :
class Controller < ApplicationController
before_filter :load_resource, :only => [:show, :edit]
def show
end
def edit
end
def index
end
#########
protected
#########
def load_resource
#resource = Model.find(params[:id])
end
end
I would simple test that #show and #edit assign the #resource thing. This works for simple scenarios pretty much ok. If the filter is applied to a lot of actions/controllers then you can extract the testing code and reuse it amongst the tests.

CanCan, how to test an rspec with a modeless, controller?

I have an admin controller w/o a model
class AdminController < ApplicationController
# Sign In Required - Devise Check
before_filter :authenticate_user!
# CanCan
before_filter :current_ability
# CanCan for Non RESTful Controllers - https://github.com/ryanb/cancan/wiki/Non-RESTful-Controllers
# We do this as there is no admin model/resouce
authorize_resource :class => false
I'm unable to figure out how to write a spec for the controller. I have the following:
describe 'Admin User' do
it "should be allow admin users to view admin#index" do
#ability_for_user_4.can :read, Admin
get :index
assert_template :index
end
end
This fails with: uninitialized constant Admin
Any ideas? Thanks
Does your spec start with require 'spec_helper' ? Most Ruby on Rails specs start with that and it will load the Rails environment into memory.
Otherwise, you need to create a mocked model so Rspec knows what an Admin is.

Admin Authorization with CanCan

A have a bunch of controllers with the Admin namespace. I want to restrict access to these unless the user is an admin. Is there a way to do this using CanCan without having to call unauthorized! in every method of every controller?
Add an application controller to your namespace and a before filter to it.
class ApplicationController < ActionController::Base
end
class Admin::ApplicationController < ApplicationController
# these goes in your namespace admin folder
before_filter :check_authorized
def check_authorized
redirect_to root_path unless can? :admin, :all
end
end
class SomeadminController < Admin::ApplicationController
def some_action
# do_stuff
end
end
The Admin Namespaces wiki page for CanCan lists out several solutions to this problem.
As #mark suggested, have a base controller for admins which checks authorization for every action.
You may not need to use CanCan at all for this if all you require is to check that users have an admin
flag.
For handling admins differently from each other (as opposed to differently from regular users only),
consider a separate AdminAbility class (this is a little off-topic, but could prove relevant).
now rails_admin has full support with Cancan, you can find it in its official website, there is a wiki page for this topic:
Rails Admin's authorization with CanCan:

Resources