Rapido is a simple, highly opinionated library that can be included into your Rails controllers to enforce standardized behavior and security.
Below is a typical example of a class using Rapido. More examples are available in the dummy application.
# Create, Index: https://www.example.com/api/documents/
# Show, update, delete: https://www.example.com/api/documents/123
class DocumentsController < ApplicationController
include Rapido::ApiController
allow_if do
current_user.is_editor?
end
allow_only :create, :delete, :index, :show, :update
attr_permitted :file, :file_name, :category
belongs_to :user, getter: :current_user
present_with DocumentPresenter
present_collection_with DocumentCollectionPresenter, :query # Query could be a string supplied as a URL parameter to search documents by name.
end
Another example where records are automatically retrieved from route parameters.
# Create, Index: https://www.example.com/api/documents/123/pages
# Show, update, delete: https://www.example.com/api/documents/123/pages/345
class PagesController < ApplicationController
include Rapido::ApiController
attr_permitted :contents, :page_number
belongs_to :document, owner: :current_user
present_with PagePresenter
present_collection_with PageCollectionPresenter
end
Accepts a method name as symbol or block. Method supplied or block must return true to allow the action to proceed, otherwise a status 401 is returned with no body.
Accepts a list of symbols. These symbols specify the controller actions that are allowed for this controller.
Accepts a list of symbols. These symbols specify the attributes that are supplied to StrongParameters as permitted parameters in create
and update
actions.
Specifies the owner of the resource. For example, if many Post
belonged to User
, then in the PostsController
, the following would be included: belongs_to :user
and Post
would be retrieved like so:
User.find(params[:user_id]).posts.find([params[:id])
.
has_one
Default false
. If true
, will treat the belongs_to
as has_one
.
owner
This is the owner of the owner - if supplied, will be used to retrieve the owner. For example, if User
belongs to Group
, Post
belongs to User
, then in the PostsController
if belongs_to :user, owner: :current_group
was supplied, then the User would be retrieved from group before Post is retrieved from user, like so:
current_group.users.find(params[:user_id]).posts.find(params[:id])
.
getter
Specifies the method to call to retrieve the owner, rather than retrieving by with URL parameters. For example, if Post
belongs to User
, then in the PostsController
if belongs_to :user, getter: :current_user
was supplied, then the post would be retrieved like so:
current_user.posts.find(params[:id])
.
This can be useful when ownership exists but is not reflected in the route structure explicitly.
build
You can create override the class Rapido::Controller build method directly in situations where the owner class does not have a build_[resource] method. Note that has_one
will execute first if set to true, ignoring any build
method you create directly, so if you do override it do not set has_one: true
.
foreign_key
Default id
. Specifies the name of the lookup column for the owner. For example, if Post
belongs to User
, then in the PostsController
if belongs_to :user, foreign_key: :token
is supplied, then the post would be retrieved like so:
User.find_by(token: id).posts.find(params[:id])
.
foreign_key_param
Default [singular owner name]_id
. Specifies the param used as the owner's foreign key. For example, if Post
belongs to User
, then in the PostsController
if belongs_to :user, foreign_key_param: :author_id
is supplied, then the post would be retrieved like so:
User.find(params[:author_id]).posts.find(params[:id])
.
Specifies the param used to retrieve the resource. For example, if Post
belongs to User
, then in the PostsController
if lookup_param :token
is supplied, then the post would be retrieved like so:
User.find_by(params[:id]).posts.find_by(token: params[:token])
.
Specifies the class that will present the resource. This class must accept the resource as the only parameter at initialization, and respond to the as_json
for output when used with the Rapido::ApiController
.
For example, if params
contained a :filter
parameter which should be used by the presenter , then the following would work:
present_with WidgetsPresenter, :filter
The initialize
method of the presenter should be structured as such:
def initialize(widgets, filter = nil)
Specifies the class that will present a collection of resources, as in the index method. Similar to presented_by
, the class must accept the resource collection as the only argument at initialization, and respond to as_json
for output when used with the Rapido::ApiController
. The collection_presented_by
can also accept a list of arguments, as symbols, that should be pulled from the params
hash and passed to presenter class at initialization as optional argments.
Collection presenters can also be provided args, similar to present_with
This will disallow any parameters in create
and update
actions.
The following filters are available to override, similar to the standard Rails action filters.
- before_build
- before_create
- after_create_success
- after_create_failure
- before_destroy
- after_destroy_success
- before_assign_attributes
- before_updat
- after_update_success
- after_update_failure
After checking out the repo, run bin/setup
to install dependencies. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Run cucumber test/test_5_1
to execute all the tests in the test application.
Bug reports and pull requests are welcome on GitHub at https://github.com/starfighter/rapido.