Crudie
Crudie is a Rails plugin handling CRUD API in controller level given a resource.
Features:
- View layer decoupled
- API parameters decoupled
- Nested resource is supported by
curdie_context - Unit test helpers provided
In a nut shell:
Say we have a resource Item and would like to provide APIs to do Creation, Reading, Updating and Deletion (CRUD) on it.
We can do it by
class ItemsController < ApplicationController
include Crudie
crudie :item
def crudie_context
Item
end
def crudie_params
params.require(:item).permit(:name)
end
endUsage:
To use Crudie, you have to
- include
Crudiein your controller class:
include Crudie- tell crudie the resource name to handle:
crudie :item- provide two helper methods:
-
crudie_context: the pool to find the resource, if the resource can be found byItem.find(id), then the pool isItem. if the resource is to be found byuser.itemson the other hand, then the pool isuser.items -
crudie_params: parameter to be passed tocreateandupdate, you can use Strong Parameters to handlerequireandpermitof the params.
APIs:
-
::crudie(resource_name[, options])-
resource_name(required): resource name in singular form, will be used to find template and set instance variables -
options(optional):-
:template_base: template base path, default to'', will be prepended to template path when rendering -
:template_extension: template extension to be appended to template path, defualt to '.json.jbuilder' -
:only: an array of method names. Only the methods in the array would be added to controller by::crudie -
:except: an array of method nmae. Method names specified in this array would NOT be added to controller.
-
-
How It Works:
Crudie defines five instance methods on controller class when crudie <resource_name> is called: index, show, create, update, and destroy,
which follows Rails routing convention.
Instance variable setting:
The defined methods set instance variables on controller after doing CRUD operations (pluralize format is covered). The instance variable can be used in view template.
Say we have a resource named items:
class ItemsController < ApplicationController
include Crudie
crudie :items
end-
create:@itemwill be set -
index:@itemswill be set -
show:@itemwill be set -
update:@itemwill be set -
destroy: no instance variable will be set
Template Rendering
The defined methods do the CRUD operations on the resource and then render templates based on action name, except delete, which renders json to hint result directly.
Say we have a resource named item, by invoking crudie :item, the create method will render template on items/create.json.jbuilder
Example
# config/route.rb
resources :user do
resources :items
end
# app/controllers/items_controller
class ItemsController < ApplicationController
include Crudie
crudie :items
def crudie_context
User.find(params[:user_id]).items
end
def crudie_params
params.require(:item).permit(:name)
end
end
# app/models/user.rb
class User < ActiveRecord::Base
has_many :items
end
# spec/controllers/items_controller_spec.rb
describe ItemsController do
include_crudie_spec_for :items, :context_name => :user
end- views to prepare:
items/create.json.jbuilderitems/index.json.jbuilderitems/show.json.jbuilderitems/update.json.jbuilder
Testing:
To Run Tests:
- install dependencies by
$ bundle install - run tests by
$ bundle exec rspec spec/
Spec helper:
Crudie provides spec helper to do
- unit tests using RSpec
- acceptance test using rspec_api_documentation
Unit test using rspec
# controller file
class ItemsController < ApplicationController
include Crudie
crudie :items
end
# spec
require 'crudie/spec'
describe ItemsController do
include Crudie::Spec::Unit
include_crudie_spec_for :items, :context_name => :user,
:only => [ :index, :show, :update ],
:except => [ :destroy ]
endAccepting Test using rspec_api_documentation
- resource without parent
# in spec/acceptance/users_spec.rb
require 'rails_helper'
require 'rspec_api_documentation/dsl'
require 'crudie/spec'
resource 'User' do
include Crudie::Spec::Acceptance
include_acceptance_spec_for :resource => {
:name => :user,
:creator => Proc.new {|index| User.create :name => index },
:context => Proc.new { User.all }
},
:parameters => {
:name => {
:desc => 'user name',
:value => 'the new user name',
:options => {
:scope => :user,
:required => true
}
}
}
end- resource with parent:
# in spec/acceptance/projects_spec.rb
require 'rails_helper'
require 'rspec_api_documentation/dsl'
require 'crudie/spec'
resource 'Projects' do
include Crudie::Spec::Acceptance
include_acceptance_spec_for :parent => {
:name => :user,
:creator => Proc.new { User.create :name => 'jack' }
},
:resource => {
:name => :project,
:creator => Proc.new {|i, user| user.projects.create :name => i },
:context => Proc.new {|parent| parent.projects }
},
:parameters => {
:name => {
:desc => 'project name',
:value => 'the new project name',
:options => {
:scope => :project,
:required => true
}
}
}
endNote:
-
parameters[:key][:value]can take either value orProc
Licence:
MIT