# Customs
**Customs** uses the power of [cancancan](https://github.com/CanCanCommunity/cancancan) (formerly known as [cancan](http://github.com/ryanb/cancan/)) to control the flow of your controllers.
It adds some magic in your rails controllers, through the cancan magic formula : ```load_and_authorize_resource```, and let you customize the flow.
**Customs** provides you:
* default cruds methods
* full control on controllers methods, steps by steps
* methods for HTTP statuses
* common errors rescue
```
class DrogsController < ApplicationController
control_and_rescue_traffic
respond_to :html, :json
load_and_authorize_resource :drog
end
```
In the given examples, we do not endorse in any way the traffic of illegal products.
Customs is watching you!
## Requirements:
* Ruby 1.9.3
* Rails 3.2.18 and higher
* Cancancan
## Installation
Add this line to your application's Gemfile:
gem 'customs'
Or install it yourself as:
$ gem install customs
Then, take a beer.
## Usage
Two methods available:
* ``control_traffic``
* ``rescue_traffic``
Or only one to bind them:
* ``control_and_rescue_traffic``
#### Example
```
class DrogsController < ApplicationController
load_and_authorize_resource :drog
control_and_rescue_traffic
respond_to :html, :json
end
```
#### Control traffic
`control_traffic` provides you default methods to list, create, update & delete resources, depending on the cancan `load_resource` arguments.
It uses exception to control the flow of data, such as:
* ActiveRecord::RecordNotFound or Mongoid::Errors::DocumentNotFound
* ActiveRecord::RecordInvalid or Mongoid::Errors::Validations
* CanCan::AccessDenied
#### Rescue traffic
`rescue_traffic` provides methods for specific HTTP statuses & routes the flow exceptions to the most appropriate one.
* 401 - `unauthorized`
* 403 - `forbidden`
* 404 - `not_found`
* 422 - `unprocessable`
#### Callbacks
Callbacks are working like rails filters :
* `before_save :make_something`
* `before_save :make_something_else, only: :create`
* `before_destroy :make_nothing`
```
class BaggagesController < ApplicationController
load_and_authorize_resource :baggage
before_save :add_illegal_content
after_save :report_to_autorithies
after_destroy :analyse_scraps
end
```
Maybe you prefer to pass a block to `create`, `update` or `destroy` ?
In this case, the block is called after the `save!` method.
```
class BaggagesController < ApplicationController
load_and_authorize_resource :baggage
def create
super do
control_content && report_to_autorithies
end
end
end
```
#### Flow customization
You can customize the controller flow by overriding any following methods:
* `resource_params` - parameters attributes, which will be used to create/update resources
* `success_response` - what happened after successfull action
* `resource_location` - where redirect on a success response (depending on the `action_name`)
For a better understanding, you have to keep in mind that `control_traffic` apply these methods with the following schema:
```
class DrogsController < ApplicationController
def create
resource.assign_attributes resource_params
resource.save!
success_response
end
def update
resource.assign_attributes resource_params
resource.save!
success_response
end
def destroy
resource.destroy
success_response
end
protected
def resource_params
params[resource_name]
end
def success_response
respond_with resource, :location => resource_location
end
def resource_location
case action_name
when 'create' then resource
when 'update' then resource
when 'destroy' then resource_name.to_s.pluralize.to_sym
end
end
end
```
##### Mass assignment
I highly recommend overriding the `resource_params` method with [Strong Parameters](http://github.com/rails/strong_parameters):
```
class SmugglersController < ApplicationController
load_and_authorize_resource :smuggler
protected
def resource_params
params.require(:smuggler).permit(:name, :skills)
end
end
```
#### Trace errors
With `rescue_traffic`, rescued errors will output something like that in you logs:
```
[Customs] Rescuing from ActionView::MissingTemplate with :not_found
```
If you need to trace the error, you just have to override the `rescue_exception_with` method:
```
def rescue_exception_with exception, method
logger.error "Rescuing from #{ exception.class } with :#{ method }"
exception.backtrace[0..10].each {|line| logger.error line }
send method
end
```
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
#### Credits
- The gem has been cutted over [cancan](https://github.com/ryanb/cancan).
- The icon has been stolen to [wikimedia.org](http://wikimedia.org).