Simple scenario

kristianmandrup edited this page Nov 10, 2011 · 13 revisions

The simple scenario is a continuation of the Quickstart guide. The Complex scenario is intended to extend this simple scenario.

Scenario assumptions

For this scenario we will assume that we have a blogging app, with these artifacts:

  • Article
  • Post
  • Comment

We will initially only have two roles:

  • Guest - a Visitor, not logged in
  • Blogger - A logged in user allowed to post Blog posts

Permissions: Guest: A visitor should be able to view/read all blogging artifacts and comment on Posts (create Comments). Blogger: A blogger should have full permissions

Configuration

We will start off by some initial configuration in the config/initializers/cantango.rb file:

CanTango.configure do |config|
  config.debug!
  config.guest.user Proc.new { Guest.instance }
  config.engines.all :off
  config.engine(:permit).set :on
end

We first turn on debugging mode so we can track the CanTango initialization and the Ability execution that performs the permission check.

We also turn off all the engines except the Permit engine. Then we define a Proc that returns a Guest user. This Proc is used in case the User class has no #guest method available. This ensures, that when we call the User Can API methods, that a Guest user will be available in case no user is logged in. We should then define Guest user permissions :)

We now have to define a Guest user class to be used for Guest users. There is usually no need to make Guest users persistent. We follow the role requirements as described in Roles and so define the methods has_role? and roles_list.

# app/models/guest.rb

class Guest
  extend  ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  def initialize
    # basic config of guest user!
  end

  def email
    'guest@info.com'
  end

  def create options = {}
    # new instance and set valid attributes?
  end

  def has_role? role
    role.to_sym == :guest
  end

  def persisted?
    false
  end
end

Note: In a coming release, we will allow you to use a default Guest user like this

CanTango.config.include_models :default_guest_user

We now create the routes, controller and views to test the app.

Here is an example of PostsController.

class PostsController < ApplicationController
  # before_filter :authenticate_user!

  def index
    @posts = Post.all
  end
end

Now we create a simple posts/index.html.haml view file where we add some access control conditions for displaying certain links and data.

%h1 Posts index
.buttons
  = link_to("New post", new_post_path) if user_can?(:create, Post)

%table
  %th
    %td View
    %td Edit
    %td Delete

  - posts.each do |post|
    %tr
      %td
        = link_to(post.title, post_path(post)) if user_can?(:read, post)
      %td
        = link_to("Edit", edit_post_path(post)) if user_can?(:edit, post)
      %td
        = link_to("Delete", delete_post_path(post)) if user_can?(:delete, post)

Now that we have the basic outlines of the app defined, we can test the permission logic by navigating around the app without logging in, acting as a visitor (Guest). We should not be able to see the links under access control, as the default permission will be false in no explicit rule gives permission.

In our blogging example, a Guest user should be able to read all blogging artifacts, but only be allowed to create Comments!

Now let's define restrictions on what the Guest can do and see, by defining a User permits for the Guest user in app/permits/guestpermit.rb. Alternatively we could define a Role permits but then we would have to assign the Guest user a role for it to work. A User permit is simpler an easier for our case.

class GuestPermit < CanTango::UserPermit
  def initialize ability
    super
  end

  protected

  def static_rules
    can :read, [Comment, Post, Article]
    can :create, Comment
  end
end 

We put the rules in the #static_rules method, to indicate that they are not depending on any external (dynamic) state. Knowing this, we could later extract these rules into a Permissions store, such as the permissions.yml YAML file.

Now as we navigate around as a user, we should only be allowed to read the artifacts and only create Comments.

Note: This assumes we have the typical REST pages (scaffolded?) for all blogger artifacts and have added similar access control logic as in the above view example for all these pages.

Note: We plan to soon develop a scaffold generator that generates view pages with this common Access Control logic in place ;)