Customs Icon

Customs

Customs uses the power of cancancan (formerly known as 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:

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