CanTango Api

The main API for CanTango

Status: Dec 9 2011

The CanTango API has now been almost fully spec'ed. All specs except for CanTango::Ability::Dsl now pass :)

Dependencies

This extension depends on the CanTango core and follows the extension conventions as described there.

Core extensions

Macro modules

  • CanTango::Api::Macros::
    • Account
    • User
    • Clazz

These macro modules allow registration of CanTango User and Account models.

Note: These should perhaps be wrapped in a Model namespace? See '-core'

Account model registration

class UserAccount
  tango_account
end

class AdminAccount
  tango_account
end

# if masquerading enabled via 'cantango-masquerade' gem
class PublisherAccount
  tango_account :masquerade
end
```

### User model registration

```ruby
class User
  tango_user 
end

class Admin
  tango_user
end

# if masquerading enabled via 'cantango-masquerade' gem
class Publisher
  tango_user :masquerade
end
```

### Generic model registration

The `Clazz` macro module uses naming conventions to determine if the model is a User or Account model.

````ruby
class UserAccount
  cantango
end

class Admin
  cantango
end

# if masquerading enabled via 'cantango-masquerade' gem
class PublisherAccount
  cantango :masquerade
end
```

## Main APIs

The main API consists of the following:

* CanTango::Api::
  * Ability
  * Can
  * Model
  * Scope
  * Session

Each of these have a specific variant for both `Account` and `User`.

## Ability

* CanTango::Api::Ability
  * Account
  * User
  * Dsl
    * Relationship
  * Relation
  * Scope


### Account

```ruby
account_ability(current_account)
current_account_ability(:admin)
```

### User

```ruby
user_ability(current_user)
current_user_ability(:editor)
```

### Dsl

The Dsl API extends the Ability API with *Relation* and *Scope* APIs. 
When The `Ability::Dsl` module is included, both these APIs are included into the target.

### Dsl - Relation

```ruby
owner_of(Post).can :edit
owner_of(Post).cannot :publish

owner_of(Post). do |owner|
  owner.can :edit
  owner.cannot :publish
end
```

This DSL creates a `Relation` object with #can and #cannot methods that delegate the wrapped ability.

### Dsl - Scope

Do relationship on Ability `#user` (also the default scope)

```ruby
scope :user do |user|
  user.owner_of(Post).can :edit
  user.owner_of(Post).cannot :publish

  user.owner_of(Post). do |owner|
    owner.can :edit
    owner.cannot :publish
  end
end
```

This DSL creates a `Scope` object that wraps an ability. It also includes the Relation API.

Do relationship on Ability `#account`

```ruby
scope :account do |account|
  account.owner_of(Post) do |owner|
    owner.can :edit
    owner.cannot :publish
  end

  account.can :create, [Blog, Article]
  account.cannot [:create, :delete], User
  # ...
end
```

## Can API

* CanTango::Api::Can
  * Account
  * User

### Account

Assuming we have registered the following types of accounts:

`CanTango.config.accounts.registered # => [:user, admin]`

Then the following methods become available when this module is included:

```ruby
user_account_can? *args
admin_account_can? *args

user_account_cannot? *args
admin_account_cannot? *args
```

The following methods are generated by this module, but by default simply forward to #current_user and #current_admin respectively. It is up to the developer to implement these methods to suit the application scenario. 

```ruby
current_user_account
current_admin_account
```

### User

Assuming we have registered the following types of accounts:

`CanTango.config.users.registered # => [:user, admin]`

Then the following methods become available when this module is included:

```ruby
user_can? *args
admin_can? *args

user_cannot? *args
admin_cannot? *args
```

It is up to the developer to make the following methods available. 
If Devise is used, methods of the form `#current_[user class]` are generated for each Devise user model.

```ruby
current_user
current_admin
```

## Model APIs

* CanTango::Api::Model
  * Account
  * User

Note: The Macros for `User` and `Account` (tango_user, tango_account, ...) might be moved under this namespace later.

### Account

```ruby
active_user
active_account
can?
cannot?
```

### User

```ruby
active_user
active_account
can?
cannot?
```

## Scope APIs

* CanTango::Api::Scope
  * Account
  * User

### Account

```ruby
scope_account scope, options, &block # alias: account_scope
real_account scope, options, &block
```

`#scope_account` can be used to make multiple AC checks within a block on a specific account. This method will use the masqueraded account if an account being masqueraded.  

`#real_account` is similar to `#scope_account`, but ignores any masquerading, applying the AC checks on the "real" account, not the one being masqueraded (faked).

### User

```ruby
scope_user scope, options, &block # alias: user_scope
real_user scope, options, &block
```

`#scope_user` can be used to make multiple AC checks within a block on a specific user. This method will use the masqueraded user if a user being masqueraded.  

`#real_user` is similar to `#scope_user`, but ignores any masquerading, applying the AC checks on the "real" user, not the one being masqueraded (faked).

## Session APIs

* CanTango::Api::Session
  * Account
  * User

### Account

Assuming we have registered the following types of accounts:

`CanTango.config.accounts.registered # => [:editor, admin]`

Then the following methods become available when this module is included:

```ruby
session_editor_account
session_admin_account
any_account *names
guest_account
active_account
active_account= account
```

`#any_account` will return the first account for which a name matches. If no account matches are found it will default to return the guest account. To find users, it will use the `#current_[account type]` methods.

### User

Assuming we have registered the following types of users:

`CanTango.config.users.registered # => [:user, admin]`

Then the following methods become available when this module is included:


```ruby
session_user
session_admin
any_account *names
guest_user
active_user
active_user= user
```

`#any_user` will return the first user for which a name matches. If no user matches are found it will default to return the guest user. To find users, it will use the `#current_[user type]` methods.


## Contributing to cantango-api

* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
* Fork the project
* Start a feature/bugfix branch
* Commit and push until you are happy with your contribution
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

## Copyright

Copyright (c) 2011 Kristian Mandrup. See LICENSE.txt for
further details.