README.md in canner-0.0.2 vs README.md in canner-0.1.0

- old
+ new

@@ -1,38 +1,25 @@ Canner ====== -Canner is an authorization gem heavily modeled after Pundit. -The goal is to take away some of the magic that exists in other auth gems out there and -provide the flexibility needed for your specific app. +Canner is an authorization gem heavily modeled after Pundit. -Who needs another auth gem? There's a bunch of very good ones out there. -Pundit, cancan, cancancan, Declarative Authorization to name a few very good alternatives. +Canner's intention is to provide you a framework for authorization that has little to no magic. +Your canner policies can be as simple or as complicated as your app requires. -Unfortunately none of those solutions had built in support for a requirement I had on a project. -My application needed to authorize a user at a given store location. +Who needs another auth gem? There's a bunch of very good ones out there. +Pundit, cancan, cancancan and Declarative Authorization to name a few alternatives. -Suppose I opened a store in Pittsburgh named Joe's Hash Rockets. The word quickly got around that Joe's -hash rockets are the best in town! Business is booming and after some market research I determine that -Cleveland is a perfect place to open another store location. +Unfortunately for me, none of those solutions had built in support for a requirement I have on the +project [Kennel Captain](http://www.kennelcaptain.com) -The problem is that I have some reports that only the store manager should see. -In any of the above listed gems if you have a manager role you could see all the reports regardless -of the store location aka store branch. +We need to authorize a user at a given store location, and that's a feature canner will support. -Canner takes this additional layer of authorization in to account. -Instead of saying: -Can the currently signed in user access this particular report. -Canner can say: -Can the currently signed in user access this particular report for this particular branch. +For details see the wiki page [Authorize with Branches ( Store Locations )](https://github.com/jacklin10/canner/wiki/Authorize-with-Branches) -To do this in other libraries you might find yourself creating roles like -pittsburgh_manager and cleveland_manager. Or maybe writing some monkey patches to hack in what you need. +Also note that canner works fine if you don't need this particular feature, its just there if you do. -Canner is designed to give you an outline of what you'll need for your app's auth needs and leaves -the level of complexity needed up to the requirements of your particular application. - ## Installation I've only tested Canner on rails 4 but it should work find in rails 3.2 apps. To install Canner just put the following in your gem file. @@ -44,18 +31,10 @@ ``` ruby bundle install ``` -After the gem is installed you'll need to run the install generator: - -``` ruby -rails g canner:install -``` - -This will create a policies directory and create the base_policy.rb - Now include canner in your application_controller.rb ``` ruby include Canner ``` @@ -64,18 +43,29 @@ ``` ruby rails g canner:policy user ``` -Restart your server +If your app gets roles from a user in a way other than @current_user.roles then you'll +need to override the fetch_roles policy method. +```ruby +rails g canner:fetch_roles +``` + +More details are available in the wiki: +[Overriding the Fetching of Roles](https://github.com/jacklin10/canner/wiki/Feed-Roles) + ## Policies As mentioned Canner is strongly influenced by Pundit and is also based on Policy objects. -Your policy objects should be named using the pattern model_namePolicy.rb. -i.e UserPolicy, CustomerPolicy, AppPolicy. +Your policy objects should be named using the following pattern: +UserPolicy, CustomerPolicy, AppPolicy. +Use the generator to save you some time: +``` rails g canner:policy <model name> ``` + Your policy models need to implement 2 methods: ``` ruby def canner_scope end @@ -83,12 +73,14 @@ end ``` ### canner_scope -The canner_scope method is used to scope the models consistently in your app. +You'll want to implement this method for each of your model policies that extend from base_policy.rb. +The canner_scope method is used to scope the authorized models consistently in your app. + For example in my app the Customers controller uses the canner_scope to ensure only Users from the current_company are displayed. ``` ruby class CustomersController < ApplicationController @@ -127,14 +119,17 @@ end end ``` -### can? +Now you don't really need to think about the auth logic when fetching a list of customers. +Just make sure you use the policy and you'll only show the users what is intended. -You probably recognize this method from Ryan Bates' cancan gem. The idea is the same as well. +Also if your policy changes at some point its a one place fix. +### can? + You use the can method to determine if the current_user is able to access an action or resource. The example above uses a straightforward case statement to determine if the current_user can access the current action or resource. @@ -146,28 +141,37 @@ when :something_random has_role?(:admin) else false end - -# Then in controller do: -can?(:something_random, :customer) ``` +# Then in controller do: +```can?(:something_random, :customer)``` In english the can method is saying: Can the currently signed in user access the something_random action? Oh, and by the way please use the CustomerPolicy's can? method to do the checking. `can?(:something_random, :user)` would use the ... you guessed it UserPolicy's can? method. +If you want to deny access by default across all model policies you could do something as simple as: + +``` ruby +def can? + false +end +``` + +in your base_policy's `can?` method + ### Force the Use of Policies Also like Pundit you can force your app to use policies. I recommend you do this so you don't forget to wrap authorization about some of your resources. -To make sure your controller actions are using the can? method add this to your +To make sure your controller actions are using the can? method add this near the top of your application_controller.rb ``` ruby after_action :ensure_auth ``` @@ -178,30 +182,39 @@ ``` Note the use of only here. You usually won't need the canner_scope on anything except for the index to be strictly enforced. +If you would like to skip for a particular controller just add +``` ruby +skip_filter :ensure_scope +``` +And / Or +``` ruby +skip_filter :ensure_auth +``` + ### Handle Canner Authorization Failures When a user does stumble onto something they don't have access to you'll want to politely tell them about it and direct the app flow as you see fit. To accomplish this in your application_controller.rb add ``` ruby - rescue_from Canner::NotAuthorizedError, with: :user_not_authorized +rescue_from Canner::NotAuthorizedError, with: :user_not_authorized ``` You can name your method whatever you want. Mine is user_not_authorized and looks like this: ``` ruby - private +private - def user_not_authorized(exception) - flash[:error] = exception.message - redirect_to(request.referrer || root_path) - end +def user_not_authorized(exception) + flash[:error] = exception.message + redirect_to(request.referrer || root_path) +end ``` ### Using can? in views You'll likely want to show or hide on screen items based on a users' role. @@ -226,6 +239,9 @@ false end end ``` +## Testing +See the wiki for some testing tips +[Testing](https://github.com/jacklin10/canner/wiki/Testing)