cancancan and devise testing for rails app - ruby-on-rails-4

I've been researching how to test my Ability and Users for a small test rails wiki i'm building and i'm having difficulty wrapping my brain around how to test either or both ?.
I think i'd like to sign_in a user as admin/editor etc. and test that user behaves like it should. I'd like to also test that Pages are displaying the correct information for an authenticated user.
This is more then one problem and i'm looking for some basic nudging less then an answer :).
I use Rspec, Cancancan, Rails 4 and devise for authentication.
I've read up on a few ways none of which worked for me:
Cancan example
Another ex i tried for cancan
Devise and rails 4 I'm using route authentication for devise.
Devise and sign_in
In any case here are my files. I'll just link to my git repo
my abilities.rb
pages.rb
users.rb
pages_controller.rb
I have factories as well but what's the trick to doing the following
Signing in users: The examples suggest using the devise test helpers then creating a signed_in user stub. I haven't quite succeeded at this yet :( so a nudge in the right direction
Devise and abilities: My understanding is I need to use the cancan/matchers then make some factories for admin/editor or any views and then do my usual tests once i've logged in a user and instantiated abilities. also failed at all the examples I tried.
Finally testing the controller for pages: I required again logging in the user with the correct ability and then testing each action for each users to see if i received the correct records back?
Maybe i'm not separating out the roles enough or i'm missing some important steps from what I could read but even a small nudge on any of these would be much appreciated.

You may have seen this, but this CanCan page https://github.com/ryanb/cancan/wiki/Testing-Abilities describes some basic high-level methodology behind testing the ability class. TL;DR Focus heavily on testing the Ability class itself and keep the controller tests light.

Related

What should I be testing for in my Django API tests?

I have started to write an API using the Django REST Framework. I am struggling to think about what tests I should be writing.
My ideas so far are...
Authentication: making sure users are logged in
Authorisation: checking users have the correct permissions
Response body: making sure all the desired fields are present
Allowed HTTP methods: making sure that users can't perform unintended actions.
Since the Django REST framework uses Django's underlying permissions system, is it really necessary to test permissions at both the model level and the API level? In this regard, it seems like some of my tests are testing for the same thing.
One of the more important things to test in an API is that it handles requests correctly. Good requests and Bad ones.

What are reasons for not using Django Admin with Django Rest Framework

It's been a while since I last used Django for a project and there have been some really great advances in the core project and the ecosystem around it.
One of those is the mature API development libraries like django-rest-framework.
So far I'm loving it. But it seems that all the guides I've found are disabling the Django Admin when using Django Rest Framework.
The reasons I've seen given were essentially "We don't need it for anything" or "We aren't using sessions, which Admin uses, so it won't work, so we're not using it."
"Don't need it" is a valid reason.
But other than that, are there reasons that it's bad practice to keep the Django Admin enabled when the project is primarily used as an API?
For my purposes, I find it convenient to manage user permissions and as a simple way to code admin only functions for dealing with the underlying data.
note: I've considered whether this question is designed to elicit opinions, which is not appropriate on SO. I believe that the answers I'm asking for will be technical or security based reasons with fact or experience based reasoning.
Totally agree.
On my current project, users are getting and setting ALL data via django-rest-framework.
Like you, I find the admin site convenient to manage user permissions, permissions groups, writing emails, sms, mobile applications push and more.
More, all these models are being translated, and translation is set in THE ADMIN SITE !!!
So, if we need a new object with translation, we do not need a new app release (example in pic of a question).
objects translations are readable and clear.
Data is organized nicely with minimal effort.
Admin get cool skins (jet / grappelli etc etc)
Language activation works like a charm in the APIViews.

How to unit test authorization globally in CakePHP

We're using CakePHP v3.1.x with the CakeDC Users plugin.
We're trying to set up our unit tests to help prevent accidentally allowing non-admins to do things they should not be allowed to do. For example, imagine that a developer creates a new admin feature with a new action in a controller. During development she sets the permissions very lax so she doesn't have to log in each time to test it (or something... you get the idea). I'm trying to write a test that will fail if she tries to push this...
Here's my idea for how to do it:
Create a test that loops over all controllers / actions in the app, and checks to see if a non-admin user is authorized.
The test has a list of every action that a non-admin user can do.
The test fails if a non-admin is allowed to do anything that's not on the list.
The idea is that every time we intentionally let non-admin users do something, the test fails, and reminds us to go update the list of exceptions. But if we accidentally allow an action without knowing it, the test fails and we fix the mistake. It's a safety catch.
My question: Is this the right way to do this? And if so, how can we dynamically generate a list of all of the apps controllers/actions?
Is this the right way to do this?
Fix the problem not the symptoms: Fix your developers behavior of committing "test" and "debug" code or whatever you want to name it. Do peer reviews or have your team leader review the commits. You could try to ask on https://workplace.stackexchange.com/ about how to deal with this situation the best. Check this question for an example.
And if so, how can we dynamically generate a list of all of the apps controllers/actions?
Use this to get a list of folders with controllers:
App::path('Controller'); // App
App::path('Controller', 'MyPlugin'); // Some plugin
Use Plugin::loaded() to get a list of all plugins.
Then use the information to read the controller classes from all the folders. You can then generate test cases (maybe trough a new task of the bake shell?) automatically because you've got a list of controllers from your app and plugin. Use reflections to get a list of public methods from the controllers and filter known public methods like initialize().
Setting up testing auth is described here.
If you write a custom test that uses an array structure describing the controllers and actions and their permissions I'm pretty sure that you'll be able to automate it by running over that array structure and using the information to run the auth tests. But honestly, I'm not going to do that work here.
Or instead of testing the code directly use Codeception acceptance testing. CakePHP has plugin for that. This will allow you to test the "real" site by having automated click-through testing. It should be pretty easy to set up a specific users session and then test against URLs for access by expecting a redirect to the login action or whatever you do.

Do I need a "Users" controller when using Devise in Rails

I am a Rails newbie. I am working on a small Rails4 project trying to improve my skills.
I am loosely following M.Hartl's tutorial.
As per the tutorial a custom user authentication is built.
However I would like to use Devise for User authentication.
Do I still need to have a Users controller as in the tutorial?
In which cases should I use/not use a Users controller when already using Devise?
Concerning the tutorial, do I just skip the controller generating part or do I have to map the actions to Devise?
You only need a users controller if you want to manage users separately from the normal signup/update process. I have a users controller so that admins can manage (create, edit, update, delete) users independently of the normal devise signup/update process.
The conflict with devise is probably because you have devise_for :users … in your routes file to set up devise and also have resources :users for your UsersController. This means that devise and your UsersController will be trying to share some of the same /users routes. You need to separate them out by changing the path that one of them is mapped to. You could either add, for example, :path => 'u' to your devise_for statement so that devise routes are mapped to /u and won't conflict with your UsersController on /users. Alternatively you could leave the devise_for alone (therefore still using /users) and instead change your UsersController routing to, for example, resources :users_admin, :controller => 'users' which would move your UsersControllers routes to be mapped to /users_admin. Note that this would change the path helpers from, for example, users_path to users_admin_path.
UPDATE
Following your comment/edit, I've had a quick look at the tutorial and I think that devise basically gives you the equivalent functionality of the user-related functionality which is developed from section 5.4 to about sections 9.1 or 9.2. (plus some extra stuff, for example, email confirmation, password reset, account lockout etc.). However, that doesn't mean that it's a drop-in replacement for that functionality, if you want to try and merge Devise with that tutorial. There are some things that look like they would work (e.g. Devise also defines a current_user method), but the routes etc. would be different, and devise splits things up into more controllers (separate controllers for registration, sign in/out, password reset…). The admin-type functionality (like in sections 2.2, 9.3, 9.4 - create/edit/delete/list other users) is what I've added a separate UsersController for in my app. Devise doesn't define a UsersController, but does use the users routes if you do devise_for :users without a path as I mentioned above.
So, more specifically:
You would only need a UsersController if you want to enable admin-type functionality allowing viewing/editing/deleting all users.
If you wanted to use devise in the tutorial, it would probably need some work to massage things to fit, changing helper links on pages etc. Sorry I'm not more specific; I haven't done that tutorial.
You would be missing out on the extra understanding that comes from doing it all manually yourself, but devise is a popular engine, so it's good to know as well. If you have the time, you could do the tutorial entirely, and then again with devise! It would help you understand some of the kind of stuff devise is doing behind the scenes. P.S: It can be instructive to look at the devise source code, even if you don't understand it all immediately.

Customizable Authencation backends not followed by Django's own login testcases. Why?

I learnt that using Customizable Authencation backends philosophy, one can create a website which accepts email addresses as usernames. But after building the corresponding logic and testing that my code is working fine, I found one issue with Django's own testcases. They were failing to follow the Customizable Authencation backend philosophy. Meaning, the testcases were actually having hardcoded values('username': 'testclient') for testing the "login" process. Why is that? Django always discourages Tight Coupling. But whats happening here?
I am not bashing Django by any means! I am a big fan and I will be, for years to come. Just want to know the reason behind this!
Update: As #dmishe pointed out those testcases should validate Django's own functionality. I understood that. But how do I let those "failing testcase" errors NOT show up when I run my testcases or run the whole project test suite?
As dmishe points out, it is not a problem that the contrib.auth tests test the functionality that is built in to the contrib.auth app. It is a problem that those tests are run for user projects by default, and it is easy to break them via normal settings customization. This is a problem the Django developers are aware of and working on possible solutions.
In the meantime, my solution is to define a simple bash script to test only the apps I want to. So instead of "./manage.py test" I run a script that does "./manage.py test app1 app2 app3...". Not perfect, but it's far from the worst of my problems :-)
Update: This commit might interest you.
I don't see a problem here, django.contrib.auth.tests should test auth app and nothing more. Thus, it should test built-in backend which is username/password combination.