upframework 0.1.0 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +37 -3
- data/app/controllers/concerns/upframework/{crud_extensions.rb → crud_endpoint.rb} +1 -2
- data/app/controllers/upframework/api_extensions.rb +30 -0
- data/app/controllers/upframework/resources_controller.rb +95 -0
- data/app/controllers/upframework/searches_controller.rb +26 -0
- data/app/searches/upframework/base_search.rb +30 -0
- data/app/services/concerns/{service_action_controller.rb → upframework/service_endpoint.rb} +1 -1
- data/app/services/upframework/base_service.rb +52 -0
- data/config/routes.rb +1 -1
- data/lib/upframework/engine.rb +4 -0
- data/lib/upframework/services/routes.rb +13 -4
- data/lib/upframework/version.rb +1 -1
- metadata +37 -5
- data/app/controllers/upframework/api_controller.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1acaf495ed6f2835c25eae1905515573ee647802879f43212ad934f6f3a4a3fb
|
4
|
+
data.tar.gz: 670163801f3ead631d142ef5840970833f48c069ba055ed19369a8a9e08fecc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6c44c39aae828c7b62cf450d47fe2d61200cc2e2e48af25c80abd6d3f631c060518b7fc15a64d912a2e3c386487a3f1b32edc6cef5bd808e22e443d5f7c863c
|
7
|
+
data.tar.gz: fa64458e28228ee45cac5d922ab848962dc313f8fb6481ffeecc1bd2d549512a73a96c6946922c65ffd57ddab6b43ab86db90120fe79440376fd3d0995f32d3e
|
data/README.md
CHANGED
@@ -1,8 +1,42 @@
|
|
1
1
|
# Upframework
|
2
|
-
|
2
|
+
Add features on top of Rails, Especially for APIs. This was created to make structural code reusable to other projects (not solving the same problem all over again). And to make the main application less bloated and only contain domain specific code as much as possible.
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
#### The following features are available.
|
5
|
+
- Creates (create, read, update, destroy) action methods for resources.
|
6
|
+
- Has render helpers for API or socket responses. ex. Converting models to its designated serializer.
|
7
|
+
- Converts snake case request params (from js standard) to underscore params (ruby standard)
|
8
|
+
- Searches layer under app/searches. Usually used for form searches.
|
9
|
+
- Services layer under app/services. For single responsibility domain-specific logic code.
|
10
|
+
- Exception notifier and API error response handler.
|
11
|
+
|
12
|
+
## Basic Usage
|
13
|
+
####Controllers
|
14
|
+
```ruby
|
15
|
+
#app/controllers
|
16
|
+
class ProjectsController < Upframework::ResourcesController
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
####Searches
|
21
|
+
```ruby
|
22
|
+
#app/searches
|
23
|
+
class ProjectSearch < Upframework::BaseSearch
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
####Services
|
28
|
+
```ruby
|
29
|
+
#app/services
|
30
|
+
class Project::SubmitService < Upframework::BaseService
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
####Routes
|
35
|
+
app/services
|
36
|
+
```ruby
|
37
|
+
#config/routes
|
38
|
+
mount Upframework::Engine => /path
|
39
|
+
```
|
6
40
|
|
7
41
|
## Installation
|
8
42
|
Add this line to your application's Gemfile:
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Upframework
|
2
|
+
module ApiExtensions
|
3
|
+
extend ::ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include ::DeviseTokenAuth::Concerns::SetUserByToken
|
7
|
+
include ::Upframework::ErrorHandler
|
8
|
+
include ::Upframework::TransformParamKeys
|
9
|
+
include ::Upframework::ServiceEndpoint
|
10
|
+
include ::Upframework::RenderExtensions
|
11
|
+
|
12
|
+
# need to skip this on non-resource controller
|
13
|
+
# > skip_authorize_resource
|
14
|
+
authorize_resource unless: :devise_controller?
|
15
|
+
|
16
|
+
rescue_from CanCan::AccessDenied do |exception|
|
17
|
+
respond_to do |format|
|
18
|
+
format.json { render json: { success: false, error: exception.message }, status: :forbidden }
|
19
|
+
format.html { redirect_to main_app.root_url, alert: exception.message }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def extra_params
|
26
|
+
[] # Override in specific controllers for custom params
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Upframework
|
2
|
+
class ResourcesController < ApplicationController
|
3
|
+
before_action :set_base_resource
|
4
|
+
|
5
|
+
def show
|
6
|
+
base_resource
|
7
|
+
|
8
|
+
yield if block_given?
|
9
|
+
render_serialized base_resource
|
10
|
+
end
|
11
|
+
|
12
|
+
def update
|
13
|
+
if base_resource.update(base_resource_params)
|
14
|
+
yield if block_given?
|
15
|
+
render_serialized base_resource
|
16
|
+
else
|
17
|
+
render_errors base_resource.errors.full_messages
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def index
|
22
|
+
base_resource
|
23
|
+
|
24
|
+
yield if block_given?
|
25
|
+
render_serialized base_resource, includes: params[:includes]
|
26
|
+
end
|
27
|
+
|
28
|
+
def create
|
29
|
+
if base_resource.save
|
30
|
+
|
31
|
+
yield if block_given?
|
32
|
+
render_serialized base_resource
|
33
|
+
else
|
34
|
+
render_errors base_resource.errors.full_messages
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy
|
39
|
+
base_resource.destroy
|
40
|
+
head :no_content
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def base_resource
|
46
|
+
if params[:id]
|
47
|
+
instance_variable_get("@#{base_resource_name}")
|
48
|
+
else
|
49
|
+
instance_variable_get("@#{base_resource_name.pluralize}")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_base_resource
|
54
|
+
data =
|
55
|
+
if params[:id]
|
56
|
+
base_resource_class.find(params[:id])
|
57
|
+
elsif action_name == 'index'
|
58
|
+
base_resource_class.accessible_by(current_ability).where(base_resource_params || {})
|
59
|
+
elsif action_name == 'create'
|
60
|
+
base_resource_class.new(base_resource_params)
|
61
|
+
end
|
62
|
+
|
63
|
+
resource_name = %w[index create].include?(action_name) \
|
64
|
+
? base_resource_name.pluralize \
|
65
|
+
: base_resource_name
|
66
|
+
|
67
|
+
instance_variable_set("@#{resource_name}", data) if data
|
68
|
+
end
|
69
|
+
|
70
|
+
def base_resource_params
|
71
|
+
base_name = base_resource_name
|
72
|
+
|
73
|
+
base_name = base_name.pluralize unless params.key?(base_name)
|
74
|
+
|
75
|
+
params.fetch(base_name).permit(*permitted_columns)
|
76
|
+
end
|
77
|
+
|
78
|
+
def permitted_columns
|
79
|
+
columns = base_resource_class.accessible_fields_by(accessors)
|
80
|
+
columns.concat(extra_params)
|
81
|
+
end
|
82
|
+
|
83
|
+
def accessors
|
84
|
+
current_user
|
85
|
+
end
|
86
|
+
|
87
|
+
def base_resource_name
|
88
|
+
controller_name.singularize
|
89
|
+
end
|
90
|
+
|
91
|
+
def base_resource_class
|
92
|
+
base_resource_name.classify.safe_constantize
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Upframework
|
2
|
+
class SearchesController < ApplicationController
|
3
|
+
skip_authorize_resource
|
4
|
+
|
5
|
+
def index
|
6
|
+
args = { current_ability: current_ability, current_user: current_user }
|
7
|
+
args.merge!(permitted_params)
|
8
|
+
|
9
|
+
resource_scope = search_class.run(args).result
|
10
|
+
render_serialized resource_scope
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def search_class
|
16
|
+
"#{params[:resource].classify}Search".constantize
|
17
|
+
end
|
18
|
+
|
19
|
+
def permitted_params
|
20
|
+
excluded_keys = %w[resource format controller action search]
|
21
|
+
permitted_keys = params.keys - excluded_keys
|
22
|
+
|
23
|
+
params.slice(*permitted_keys).permit(permitted_keys)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Upframework::BaseSearch < Upframework::BaseService
|
2
|
+
DEFAULT_PAGE = 1
|
3
|
+
DEFAULT_PER_PAGE = 12
|
4
|
+
|
5
|
+
def result
|
6
|
+
@model_scope
|
7
|
+
end
|
8
|
+
|
9
|
+
def query(field)
|
10
|
+
@model_scope = yield if field.present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def paginate_scope
|
14
|
+
return if @model_scope.nil?
|
15
|
+
|
16
|
+
@model_scope = @model_scope.
|
17
|
+
page(@page || DEFAULT_PAGE).
|
18
|
+
per(@per_page || DEFAULT_PER_PAGE).
|
19
|
+
order(created_at: :desc)
|
20
|
+
end
|
21
|
+
|
22
|
+
module ExecuteWrapper
|
23
|
+
def execute
|
24
|
+
super
|
25
|
+
paginate_scope
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
include ExecuteWrapper
|
30
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Upframework
|
2
|
+
class BaseService
|
3
|
+
attr_reader :errors
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def run(attributes = {})
|
7
|
+
attributes = Hash[attributes.to_h.map { |k, v| [k.to_sym, v] }]
|
8
|
+
new(**attributes).tap(&:execute)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(**attributes)
|
13
|
+
@errors = []
|
14
|
+
|
15
|
+
self.class.send(:attr_reader, *attributes.keys)
|
16
|
+
|
17
|
+
#TODO: Remove. This should be handled on the child class.
|
18
|
+
attributes.each do |key, value|
|
19
|
+
instance_variable_set("@#{key}", value)
|
20
|
+
end
|
21
|
+
|
22
|
+
post_initialize(**attributes)
|
23
|
+
end
|
24
|
+
|
25
|
+
def post_initialize(**attributes)
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute
|
29
|
+
end
|
30
|
+
|
31
|
+
def result
|
32
|
+
end
|
33
|
+
|
34
|
+
def success?
|
35
|
+
@errors.blank?
|
36
|
+
end
|
37
|
+
|
38
|
+
def error?
|
39
|
+
@errors.present?
|
40
|
+
end
|
41
|
+
|
42
|
+
def error_messages
|
43
|
+
@errors.join('. ')
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def add_error(error)
|
49
|
+
@errors << error
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/config/routes.rb
CHANGED
data/lib/upframework/engine.rb
CHANGED
@@ -1,17 +1,26 @@
|
|
1
1
|
module Upframework
|
2
2
|
module Services
|
3
3
|
module Routes
|
4
|
-
def self.load
|
4
|
+
def self.load(namespace: nil, **options)
|
5
|
+
scope_name = namespace
|
6
|
+
|
5
7
|
Rails.application.routes.draw do
|
6
8
|
source_path = Rails.root.join('app', 'services')
|
7
9
|
|
8
|
-
|
10
|
+
service_routes = proc do
|
9
11
|
Dir.glob("#{source_path}/*/").map{ |e| File.basename e }.each do |resource|
|
10
|
-
#
|
11
|
-
#
|
12
|
+
# Create a post route for services
|
13
|
+
# ex.
|
14
|
+
# POST users/service/my_custom_service
|
12
15
|
post "#{resource}/service/:service_name", to: "#{resource}#service"
|
13
16
|
end
|
14
17
|
end
|
18
|
+
|
19
|
+
if scope_name
|
20
|
+
namespace scope_name, defaults: { format: :json }, &service_routes
|
21
|
+
else
|
22
|
+
service_routes.call
|
23
|
+
end
|
15
24
|
end
|
16
25
|
end
|
17
26
|
end
|
data/lib/upframework/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: upframework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jude_cali
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -30,6 +30,34 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 6.0.2.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: cancancan
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 3.1.0
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.1.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: fast_jsonapi
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.5'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.5'
|
33
61
|
description: Rails framework extensions
|
34
62
|
email:
|
35
63
|
- jcalimbas@fullscale.io
|
@@ -42,16 +70,20 @@ files:
|
|
42
70
|
- Rakefile
|
43
71
|
- app/assets/config/upframework_manifest.js
|
44
72
|
- app/assets/stylesheets/upframework/application.css
|
45
|
-
- app/controllers/concerns/upframework/
|
73
|
+
- app/controllers/concerns/upframework/crud_endpoint.rb
|
46
74
|
- app/controllers/concerns/upframework/error_handler.rb
|
47
75
|
- app/controllers/concerns/upframework/render_extensions.rb
|
48
76
|
- app/controllers/concerns/upframework/transform_param_keys.rb
|
49
|
-
- app/controllers/upframework/
|
77
|
+
- app/controllers/upframework/api_extensions.rb
|
78
|
+
- app/controllers/upframework/resources_controller.rb
|
79
|
+
- app/controllers/upframework/searches_controller.rb
|
50
80
|
- app/helpers/upframework/application_helper.rb
|
51
81
|
- app/jobs/upframework/application_job.rb
|
52
82
|
- app/mailers/upframework/application_mailer.rb
|
53
83
|
- app/models/upframework/application_record.rb
|
54
|
-
- app/
|
84
|
+
- app/searches/upframework/base_search.rb
|
85
|
+
- app/services/concerns/upframework/service_endpoint.rb
|
86
|
+
- app/services/upframework/base_service.rb
|
55
87
|
- app/views/layouts/upframework/application.html.erb
|
56
88
|
- config/routes.rb
|
57
89
|
- lib/tasks/upframework_tasks.rake
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module Upframework
|
2
|
-
class ApiController < ::ApplicationController
|
3
|
-
include ::DeviseTokenAuth::Concerns::SetUserByToken
|
4
|
-
include ::Upframework::ErrorHandler
|
5
|
-
include ::Upframework::TransformParamKeys
|
6
|
-
include ::Upframework::CrudExtensions
|
7
|
-
include ::Upframework::RenderExtensions
|
8
|
-
include ::Upframework::ServiceActionController
|
9
|
-
|
10
|
-
before_action :authenticate!
|
11
|
-
|
12
|
-
# need to skip this on non-resource controller
|
13
|
-
# > skip_authorize_resource
|
14
|
-
authorize_resource
|
15
|
-
|
16
|
-
rescue_from CanCan::AccessDenied do |exception|
|
17
|
-
respond_to do |format|
|
18
|
-
format.json { render json: { success: false, error: exception.message }, status: :forbidden }
|
19
|
-
format.html { redirect_to main_app.root_url, alert: exception.message }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def authenticate!
|
24
|
-
super || authenticate_user!
|
25
|
-
end
|
26
|
-
|
27
|
-
protected
|
28
|
-
|
29
|
-
def extra_params
|
30
|
-
[] # Override in specific controllers for custom params
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|