simple_resource_controller 0.1.6 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +85 -0
- data/lib/simple_resource_controller/configurator.rb +1 -1
- data/lib/simple_resource_controller/controller/actions.rb +82 -0
- data/lib/simple_resource_controller/controller/config.rb +37 -0
- data/lib/simple_resource_controller/controller/implementation/format/api.rb +66 -0
- data/lib/simple_resource_controller/controller/implementation/format/html.rb +69 -0
- data/lib/simple_resource_controller/controller/implementation.rb +152 -0
- data/lib/simple_resource_controller/controller.rb +29 -288
- data/lib/simple_resource_controller/railtie.rb +2 -0
- data/lib/simple_resource_controller/version.rb +1 -1
- data/simple_resource_controller.gemspec +7 -5
- metadata +52 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41e99ec931e6de3bf1a4d68cb23fe2357e8671c97ebbcf1bf7aecdb001bbc1f5
|
4
|
+
data.tar.gz: 1d18e94778a8f51b3a7bfe404e3a91b07a6889df7b632968e5735a34050d3e26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 020cfb5e4304c2f7527eecee4f62973d320837fc725a0d8b503440c674e67f1d88eac61bfb8553da6f663434f737787e10dcdc2560686e83949ee4b2e0f8ffac
|
7
|
+
data.tar.gz: cac6d60eff27e7688dc685a0f2193f196a47e4bc36ee05de6eeb4131d1943e83671e4157a2d565bcb90d13aa83ed2dc9339a1355596f541ac5f51417f49d91d3
|
data/README.md
CHANGED
@@ -63,6 +63,86 @@ class AnotherArticlesController < ApplicationController
|
|
63
63
|
end
|
64
64
|
```
|
65
65
|
|
66
|
+
### API examples
|
67
|
+
|
68
|
+
Gem suppports [jbuilder](https://github.com/rails/jbuilder) and [activemodel_serializer](https://github.com/rails-api/active_model_serializers) as API serializers
|
69
|
+
|
70
|
+
#### JBuilder
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class AnotherArticlesController < ApplicationController
|
74
|
+
resource_actions :crud
|
75
|
+
resource_api jbuilder: true
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def permitted_params
|
80
|
+
params.require(:article).permit(:title)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
But you will also need to add all view files for your actions, including `new` and `edit`.
|
86
|
+
|
87
|
+
**You can find example inside tests.**
|
88
|
+
|
89
|
+
#### ActiveModel::Serializer
|
90
|
+
|
91
|
+
Minimum config:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
class AnotherArticlesController < ApplicationController
|
95
|
+
resource_actions :crud
|
96
|
+
resource_api activemodel_serializer: { }
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def permitted_params
|
101
|
+
params.require(:article).permit(:title)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
All options:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
class AnotherArticlesController < ApplicationController
|
110
|
+
resource_actions :crud
|
111
|
+
resource_api activemodel_serializer: { collection_serializer: MyCollectionSerializer, resource_serializer: MyArticleSerializer, error_serializer: MyErrorSerializer }
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def permitted_params
|
116
|
+
params.require(:article).permit(:title)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
With redefined options:
|
122
|
+
|
123
|
+
**Important note: you should always set the error_serializer**
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
class AnotherArticlesController < ApplicationController
|
127
|
+
resource_actions :crud
|
128
|
+
resource_api activemodel_serializer: { collection_serializer: MyCollectionSerializer, resource_serializer: MyArticleSerializer, error_serializer: MyErrorSerializer }
|
129
|
+
|
130
|
+
# will use the AnotherArticleSerializer when success
|
131
|
+
# will use the MyErrorSerializer when failure
|
132
|
+
def update
|
133
|
+
update! serializer: AnotherArticleSerializer
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def permitted_params
|
139
|
+
params.require(:article).permit(:title)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
**You can find example inside tests.**
|
145
|
+
|
66
146
|
### Controller configuration
|
67
147
|
|
68
148
|
The first required configuration is an action name.
|
@@ -394,6 +474,11 @@ This is my favorite one. The `responders` gem follows the next logic - if a reco
|
|
394
474
|
If you will get this exception - check your ActiveRecord callbacks, your code has some smells.
|
395
475
|
|
396
476
|
|
477
|
+
#### `error_serializer should be configured for the activemodel API`
|
478
|
+
|
479
|
+
You are trying to use the `resource_api` DSL to setup the activemodel_serializer, faced with the validation error in create or update action.
|
480
|
+
But didn't configured an error serializer: `resource_api activemodel_serializer: { error_serializer: MyErrorSerializer }`
|
481
|
+
|
397
482
|
## Contributing
|
398
483
|
|
399
484
|
Bug reports and pull requests are welcome on GitHub at https://github.com/c3gdlk/simple_resource_controller. This project is intended to be a safe, welcoming space for collaboration.
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module SimpleResourceController
|
2
|
+
module Controller
|
3
|
+
module Actions
|
4
|
+
module Index
|
5
|
+
def index(options={}, &block)
|
6
|
+
unless block_given?
|
7
|
+
if current_controller_api?
|
8
|
+
api_before_index_response_callback(options)
|
9
|
+
else
|
10
|
+
html_before_index_response_callback(options)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
respond_with collection, options, &block
|
15
|
+
end
|
16
|
+
alias :index! :index
|
17
|
+
end
|
18
|
+
|
19
|
+
module Show
|
20
|
+
def show(options={}, &block)
|
21
|
+
unless block_given?
|
22
|
+
if current_controller_api?
|
23
|
+
api_before_show_response_callback(options)
|
24
|
+
else
|
25
|
+
html_before_show_response_callback(options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
respond_with resource, options, &block
|
30
|
+
end
|
31
|
+
alias :show! :show
|
32
|
+
end
|
33
|
+
|
34
|
+
module New
|
35
|
+
def new(options={}, &block)
|
36
|
+
build_resource
|
37
|
+
respond_with resource, options, &block
|
38
|
+
end
|
39
|
+
alias :new! :new
|
40
|
+
end
|
41
|
+
|
42
|
+
module Create
|
43
|
+
def create(options={}, &block)
|
44
|
+
build_resource
|
45
|
+
save_resource_and_respond!(options, &block)
|
46
|
+
end
|
47
|
+
alias :create! :create
|
48
|
+
end
|
49
|
+
|
50
|
+
module Edit
|
51
|
+
def edit(options={}, &block)
|
52
|
+
respond_with resource, options, &block
|
53
|
+
end
|
54
|
+
alias :edit! :edit
|
55
|
+
end
|
56
|
+
|
57
|
+
module Update
|
58
|
+
def update(options={}, &block)
|
59
|
+
save_resource_and_respond!(options, &block)
|
60
|
+
end
|
61
|
+
alias :update! :update
|
62
|
+
end
|
63
|
+
|
64
|
+
module Destroy
|
65
|
+
def destroy(options={}, &block)
|
66
|
+
resource.destroy
|
67
|
+
|
68
|
+
unless block_given?
|
69
|
+
if current_controller_api?
|
70
|
+
api_before_destroy_response_callback(options)
|
71
|
+
else
|
72
|
+
html_before_destroy_response_callback(options)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
respond_with resource, options, &block
|
77
|
+
end
|
78
|
+
alias :destroy! :destroy
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module SimpleResourceController
|
2
|
+
module Controller
|
3
|
+
module Config
|
4
|
+
def resource_class_config
|
5
|
+
@resource_class_config
|
6
|
+
end
|
7
|
+
|
8
|
+
def resource_class(value)
|
9
|
+
@resource_class_config = value
|
10
|
+
end
|
11
|
+
|
12
|
+
def resource_context_config
|
13
|
+
@resource_context_config
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_context(*values)
|
17
|
+
@resource_context_config = values
|
18
|
+
end
|
19
|
+
|
20
|
+
def paginate_collection_config
|
21
|
+
@paginate_collection_config
|
22
|
+
end
|
23
|
+
|
24
|
+
def paginate_collection(value)
|
25
|
+
@paginate_collection_config = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def api_config
|
29
|
+
@api_config
|
30
|
+
end
|
31
|
+
|
32
|
+
def resource_api(value)
|
33
|
+
@api_config = value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module SimpleResourceController
|
2
|
+
module Controller
|
3
|
+
module Implementation
|
4
|
+
module Format
|
5
|
+
module Api
|
6
|
+
private
|
7
|
+
|
8
|
+
def api_before_index_response_callback(options)
|
9
|
+
if activemodel_serializer?
|
10
|
+
resource_serializer = self.class.api_config.dig(:activemodel_serializer, :resource_serializer)
|
11
|
+
collection_serializer = self.class.api_config.dig(:activemodel_serializer, :collection_serializer)
|
12
|
+
|
13
|
+
options[:json] ||= collection
|
14
|
+
options[:each_serializer] ||= resource_serializer if resource_serializer.present?
|
15
|
+
options[:serializer] ||= collection_serializer if collection_serializer.present?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def api_before_show_response_callback(options)
|
20
|
+
if activemodel_serializer?
|
21
|
+
resource_serializer = self.class.api_config.dig(:activemodel_serializer, :resource_serializer)
|
22
|
+
options[:json] ||= resource
|
23
|
+
options[:serializer] ||= resource_serializer if resource_serializer.present?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def api_before_save_success_response_callback(options)
|
28
|
+
options[:status] ||= :created if action_name == "create"
|
29
|
+
|
30
|
+
if activemodel_serializer?
|
31
|
+
resource_serializer = self.class.api_config.dig(:activemodel_serializer, :resource_serializer)
|
32
|
+
options[:json] ||= resource
|
33
|
+
options[:serializer] ||= resource_serializer if resource_serializer.present?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def api_before_save_failure_response_callback(options)
|
38
|
+
if activemodel_serializer?
|
39
|
+
error_serializer = self.class.api_config.dig(:activemodel_serializer, :error_serializer)
|
40
|
+
|
41
|
+
raise "error_serializer should be configured for the activemodel API" unless error_serializer.present?
|
42
|
+
options[:json] ||= resource
|
43
|
+
options[:serializer] = error_serializer
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def api_before_destroy_response_callback(options)
|
48
|
+
if activemodel_serializer?
|
49
|
+
resource_serializer = self.class.api_config.dig(:activemodel_serializer, :resource_serializer)
|
50
|
+
options[:json] ||= resource
|
51
|
+
options[:serializer] ||= resource_serializer if resource_serializer.present?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def current_controller_api?
|
56
|
+
self.class.api_config.present?
|
57
|
+
end
|
58
|
+
|
59
|
+
def activemodel_serializer?
|
60
|
+
current_controller_api? && self.class.api_config.dig(:activemodel_serializer).present?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module SimpleResourceController
|
2
|
+
module Controller
|
3
|
+
module Implementation
|
4
|
+
module Format
|
5
|
+
module Html
|
6
|
+
private
|
7
|
+
|
8
|
+
def html_before_index_response_callback(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def html_before_show_response_callback(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def html_before_save_success_response_callback(options)
|
15
|
+
options[:location] ||= after_save_redirect_path
|
16
|
+
setup_flash_messages(after_create_messages) if action_name == "create"
|
17
|
+
setup_flash_messages(after_update_messages) if action_name == "update"
|
18
|
+
end
|
19
|
+
|
20
|
+
def api_before_save_failure_response_callback(options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def html_before_destroy_response_callback(options)
|
24
|
+
options[:location] ||= after_destroy_redirect_path
|
25
|
+
setup_flash_messages(after_destroy_messages)
|
26
|
+
end
|
27
|
+
|
28
|
+
# :nocov:
|
29
|
+
def after_save_redirect_path
|
30
|
+
raise NotImplementedError, "Need to implement the after_save_redirect_path method"
|
31
|
+
end
|
32
|
+
# :nocov:
|
33
|
+
|
34
|
+
# :nocov:
|
35
|
+
def after_destroy_redirect_path
|
36
|
+
raise NotImplementedError, "Need to implement the after_destroy_redirect_path method"
|
37
|
+
end
|
38
|
+
# :nocov:
|
39
|
+
|
40
|
+
def after_create_messages
|
41
|
+
after_save_messages
|
42
|
+
end
|
43
|
+
|
44
|
+
def after_update_messages
|
45
|
+
after_save_messages
|
46
|
+
end
|
47
|
+
|
48
|
+
def after_destroy_messages
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def after_save_messages
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def setup_flash_messages(messages)
|
57
|
+
return unless messages.present?
|
58
|
+
|
59
|
+
raise 'Messages should be specified with Hash' unless messages.is_a?(Hash)
|
60
|
+
|
61
|
+
messages.each do |key, message|
|
62
|
+
flash[key] = message
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require_relative './implementation/format/api'
|
2
|
+
require_relative './implementation/format/html'
|
3
|
+
|
4
|
+
module SimpleResourceController
|
5
|
+
module Controller
|
6
|
+
module Implementation
|
7
|
+
include Format::Api
|
8
|
+
include Format::Html
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def collection
|
13
|
+
return instance_variable_get(:"@#{collection_name}") if instance_variable_get(:"@#{collection_name}").present?
|
14
|
+
instance_variable_set(:"@#{collection_name}", apply_scopes_and_pagination(association_chain))
|
15
|
+
end
|
16
|
+
|
17
|
+
def apply_scopes_and_pagination(chain)
|
18
|
+
if respond_to?(:apply_scopes, true)
|
19
|
+
chain = apply_scopes(chain)
|
20
|
+
end
|
21
|
+
|
22
|
+
per_page = self.class.paginate_collection_config
|
23
|
+
|
24
|
+
if per_page.present?
|
25
|
+
raise 'Please install Kaminari' unless defined?(::Kaminari)
|
26
|
+
|
27
|
+
chain = chain.page(params[:page]).per(params[:per_page] || per_page)
|
28
|
+
else
|
29
|
+
chain = chain.all
|
30
|
+
end
|
31
|
+
|
32
|
+
chain
|
33
|
+
end
|
34
|
+
|
35
|
+
def collection_name
|
36
|
+
resource_name.pluralize
|
37
|
+
end
|
38
|
+
|
39
|
+
def resource_class_name
|
40
|
+
self.class.resource_class_config || self.class.name.split('::').last.gsub('Controller', '').singularize
|
41
|
+
end
|
42
|
+
|
43
|
+
def resource_class
|
44
|
+
resource_class_name.constantize
|
45
|
+
end
|
46
|
+
|
47
|
+
def resource_name
|
48
|
+
resource_class_name.split('::').last.underscore
|
49
|
+
end
|
50
|
+
|
51
|
+
def resource_relation_name
|
52
|
+
resource_class_name.underscore.pluralize
|
53
|
+
end
|
54
|
+
|
55
|
+
def association_chain
|
56
|
+
self.class.resource_context_config.present? ? association_chain_by_context : resource_class
|
57
|
+
end
|
58
|
+
|
59
|
+
def association_chain_by_context
|
60
|
+
specified_scopes.reduce(default_context) do |context, scope|
|
61
|
+
raise "#{context.inspect} hasn't relation #{scope}" unless context.respond_to? scope
|
62
|
+
|
63
|
+
context.public_send(scope)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def default_context
|
68
|
+
context_method = self.class.resource_context_config.first
|
69
|
+
|
70
|
+
if self.respond_to? context_method, true
|
71
|
+
context = send(context_method)
|
72
|
+
elsif params["#{context_method}_id"].present?
|
73
|
+
class_name = context_method.to_s.classify
|
74
|
+
context_class = class_name.safe_constantize
|
75
|
+
|
76
|
+
if context_class.present?
|
77
|
+
context = context_class.find(params["#{context_method}_id"])
|
78
|
+
else
|
79
|
+
raise "Could not find model #{class_name} by param #{context_method}_id"
|
80
|
+
end
|
81
|
+
else
|
82
|
+
raise "Undefined context method #{context_method}"
|
83
|
+
end
|
84
|
+
|
85
|
+
context
|
86
|
+
end
|
87
|
+
|
88
|
+
def specified_scopes
|
89
|
+
if self.class.resource_context_config.size > 1
|
90
|
+
self.class.resource_context_config[1..-1]
|
91
|
+
else
|
92
|
+
[resource_relation_name.to_sym]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_resource
|
97
|
+
return instance_variable_get(:"@#{resource_name}") if instance_variable_get(:"@#{resource_name}").present?
|
98
|
+
|
99
|
+
instance = association_chain.is_a?(ActiveRecord::Relation) ? association_chain.build : association_chain.new
|
100
|
+
instance.assign_attributes(permitted_params) if action_name == "create"
|
101
|
+
|
102
|
+
instance_variable_set(:"@#{resource_name}", instance)
|
103
|
+
end
|
104
|
+
|
105
|
+
def resource
|
106
|
+
return instance_variable_get(:"@#{resource_name}") if instance_variable_get(:"@#{resource_name}").present?
|
107
|
+
|
108
|
+
instance = association_chain.find(params[:id])
|
109
|
+
instance.assign_attributes(permitted_params) if action_name == "update"
|
110
|
+
|
111
|
+
instance_variable_set(:"@#{resource_name}", instance)
|
112
|
+
end
|
113
|
+
|
114
|
+
def save_resource_and_respond!(options={}, &block)
|
115
|
+
success = resource.save
|
116
|
+
|
117
|
+
# process not saved result because of failed callback or another ActiveRecord magic
|
118
|
+
if resource.valid? && !success
|
119
|
+
resource.errors[:base] << resource_wasnt_saved_message
|
120
|
+
end
|
121
|
+
|
122
|
+
unless block_given?
|
123
|
+
if success
|
124
|
+
if current_controller_api?
|
125
|
+
api_before_save_success_response_callback(options)
|
126
|
+
else
|
127
|
+
html_before_save_success_response_callback(options)
|
128
|
+
end
|
129
|
+
else
|
130
|
+
if current_controller_api?
|
131
|
+
api_before_save_failure_response_callback(options)
|
132
|
+
else
|
133
|
+
api_before_save_failure_response_callback(options)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
respond_with resource, options, &block
|
139
|
+
end
|
140
|
+
|
141
|
+
def resource_wasnt_saved_message
|
142
|
+
raise 'Too many Rails magic. Please check your code'
|
143
|
+
end
|
144
|
+
|
145
|
+
# :nocov:
|
146
|
+
def permitted_params
|
147
|
+
raise NotImplementedError, "Need to implement the permitted_params method"
|
148
|
+
end
|
149
|
+
# :nocov:
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -1,305 +1,46 @@
|
|
1
|
+
require_relative './controller/actions'
|
2
|
+
require_relative './controller/config'
|
3
|
+
require_relative './controller/implementation'
|
4
|
+
|
1
5
|
module SimpleResourceController
|
2
6
|
module Controller
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
respond_with resource, options, &block
|
13
|
-
end
|
14
|
-
alias :show! :show
|
15
|
-
end
|
16
|
-
|
17
|
-
module New
|
18
|
-
def new(options={}, &block)
|
19
|
-
build_resource
|
20
|
-
respond_with resource, options, &block
|
21
|
-
end
|
22
|
-
alias :new! :new
|
23
|
-
end
|
24
|
-
|
25
|
-
module Create
|
26
|
-
def create(options={}, &block)
|
27
|
-
build_resource
|
28
|
-
success = save_resource_and_respond!(options, &block)
|
29
|
-
ensure
|
30
|
-
setup_flash_messages(after_create_messages) if success
|
31
|
-
end
|
32
|
-
alias :create! :create
|
33
|
-
end
|
34
|
-
|
35
|
-
module Edit
|
36
|
-
def edit(options={}, &block)
|
37
|
-
respond_with resource, options, &block
|
38
|
-
end
|
39
|
-
alias :edit! :edit
|
40
|
-
end
|
41
|
-
|
42
|
-
module Update
|
43
|
-
def update(options={}, &block)
|
44
|
-
success = save_resource_and_respond!(options, &block)
|
45
|
-
ensure
|
46
|
-
setup_flash_messages(after_update_messages) if success
|
47
|
-
end
|
48
|
-
alias :update! :update
|
49
|
-
end
|
50
|
-
|
51
|
-
module Destroy
|
52
|
-
def destroy(options={}, &block)
|
53
|
-
destroy_resource_and_respond!(options, &block)
|
54
|
-
ensure
|
55
|
-
setup_flash_messages(after_destroy_messages)
|
56
|
-
end
|
57
|
-
alias :destroy! :destroy
|
58
|
-
end
|
59
|
-
|
60
|
-
module CommonMethods
|
61
|
-
private
|
62
|
-
|
63
|
-
def collection
|
64
|
-
return instance_variable_get(:"@#{collection_name}") if instance_variable_get(:"@#{collection_name}").present?
|
65
|
-
instance_variable_set(:"@#{collection_name}", apply_scopes_and_pagination(association_chain))
|
66
|
-
end
|
67
|
-
|
68
|
-
def apply_scopes_and_pagination(chain)
|
69
|
-
if respond_to?(:apply_scopes, true)
|
70
|
-
chain = apply_scopes(chain)
|
71
|
-
end
|
72
|
-
|
73
|
-
per_page = self.class.paginate_collection_config
|
74
|
-
|
75
|
-
if per_page.present?
|
76
|
-
raise 'Please install Kaminari' unless defined?(Kaminari)
|
77
|
-
|
78
|
-
chain = chain.page(params[:page]).per(params[:per_page] || per_page)
|
79
|
-
else
|
80
|
-
chain = chain.all
|
81
|
-
end
|
82
|
-
|
83
|
-
chain
|
84
|
-
end
|
85
|
-
|
86
|
-
def collection_name
|
87
|
-
resource_name.pluralize
|
88
|
-
end
|
89
|
-
|
90
|
-
def resource_class_name
|
91
|
-
self.class.resource_class_config || self.class.name.split('::').last.gsub('Controller', '').singularize
|
92
|
-
end
|
93
|
-
|
94
|
-
def resource_class
|
95
|
-
resource_class_name.constantize
|
96
|
-
end
|
97
|
-
|
98
|
-
def resource_name
|
99
|
-
resource_class_name.split('::').last.underscore
|
100
|
-
end
|
101
|
-
|
102
|
-
def resource_relation_name
|
103
|
-
resource_class_name.underscore.pluralize
|
104
|
-
end
|
105
|
-
|
106
|
-
def association_chain
|
107
|
-
self.class.resource_context_config.present? ? association_chain_by_context : resource_class
|
108
|
-
end
|
109
|
-
|
110
|
-
def association_chain_by_context
|
111
|
-
specified_scopes.reduce(default_context) do |context, scope|
|
112
|
-
raise "#{context.inspect} hasn't relation #{scope}" unless context.respond_to? scope
|
113
|
-
|
114
|
-
context.public_send(scope)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def default_context
|
119
|
-
context_method = self.class.resource_context_config.first
|
120
|
-
|
121
|
-
if self.respond_to? context_method, true
|
122
|
-
context = send(context_method)
|
123
|
-
elsif params["#{context_method}_id"].present?
|
124
|
-
class_name = context_method.to_s.classify
|
125
|
-
context_class = class_name.safe_constantize
|
126
|
-
|
127
|
-
if context_class.present?
|
128
|
-
context = context_class.find(params["#{context_method}_id"])
|
129
|
-
else
|
130
|
-
raise "Could not find model #{class_name} by param #{context_method}_id"
|
131
|
-
end
|
132
|
-
else
|
133
|
-
raise "Undefined context method #{context_method}"
|
134
|
-
end
|
135
|
-
|
136
|
-
context
|
137
|
-
end
|
7
|
+
DEPENDENCIES_MAP = {
|
8
|
+
index: Actions::Index,
|
9
|
+
show: Actions::Show,
|
10
|
+
new: Actions::New,
|
11
|
+
create: Actions::Create,
|
12
|
+
edit: Actions::Edit,
|
13
|
+
update: Actions::Update,
|
14
|
+
destroy: Actions::Destroy
|
15
|
+
}.freeze
|
138
16
|
|
139
|
-
|
140
|
-
if self.class.resource_context_config.size > 1
|
141
|
-
self.class.resource_context_config[1..-1]
|
142
|
-
else
|
143
|
-
[resource_relation_name.to_sym]
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def build_resource
|
148
|
-
return instance_variable_get(:"@#{resource_name}") if instance_variable_get(:"@#{resource_name}").present?
|
149
|
-
|
150
|
-
new_instance = association_chain.is_a?(ActiveRecord::Relation) ? association_chain.build : association_chain.new
|
151
|
-
instance_variable_set(:"@#{resource_name}", new_instance)
|
152
|
-
end
|
153
|
-
|
154
|
-
def resource
|
155
|
-
return instance_variable_get(:"@#{resource_name}") if instance_variable_get(:"@#{resource_name}").present?
|
156
|
-
instance_variable_set(:"@#{resource_name}", association_chain.find(params[:id]))
|
157
|
-
end
|
158
|
-
|
159
|
-
def destroy_resource_and_respond!(options={}, &block)
|
160
|
-
resource.destroy
|
161
|
-
|
162
|
-
unless block_given? || options[:location].present?
|
163
|
-
options[:location] = after_destroy_redirect_path
|
164
|
-
end
|
165
|
-
|
166
|
-
respond_with resource, options, &block
|
167
|
-
end
|
168
|
-
|
169
|
-
def save_resource_and_respond!(options={}, &block)
|
170
|
-
result = resource.update(permitted_params)
|
171
|
-
|
172
|
-
# process not saved result because of failed callback or another ActiveRecord magic
|
173
|
-
if resource.valid? && !result.present?
|
174
|
-
resource.errors[:base] << resource_wasnt_saved_message
|
175
|
-
end
|
176
|
-
|
177
|
-
if result.present?
|
178
|
-
unless block_given? || options[:location].present?
|
179
|
-
options[:location] = after_save_redirect_path
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
respond_with resource, options, &block
|
184
|
-
|
185
|
-
result
|
186
|
-
end
|
187
|
-
|
188
|
-
def resource_wasnt_saved_message
|
189
|
-
raise 'Too many Rails magic. Please check your code'
|
190
|
-
end
|
191
|
-
|
192
|
-
def after_create_messages
|
193
|
-
after_save_messages
|
194
|
-
end
|
195
|
-
|
196
|
-
def after_update_messages
|
197
|
-
after_save_messages
|
198
|
-
end
|
199
|
-
|
200
|
-
def after_destroy_messages
|
201
|
-
nil
|
202
|
-
end
|
203
|
-
|
204
|
-
def after_save_messages
|
205
|
-
nil
|
206
|
-
end
|
207
|
-
|
208
|
-
def setup_flash_messages(messages)
|
209
|
-
return unless messages.present?
|
17
|
+
HELPER_METHODS = [:resource, :collection].freeze
|
210
18
|
|
211
|
-
|
19
|
+
ALL_ACTIONS_ALIAS = :crud
|
212
20
|
|
213
|
-
|
214
|
-
|
215
|
-
|
21
|
+
def self.build(controller_class, actions)
|
22
|
+
unless actions.include?(ALL_ACTIONS_ALIAS)
|
23
|
+
raise 'Unknown action name' unless (actions - DEPENDENCIES_MAP.keys).size.zero?
|
216
24
|
end
|
217
25
|
|
218
|
-
|
219
|
-
def after_save_redirect_path
|
220
|
-
raise 'Not Implemented'
|
221
|
-
end
|
222
|
-
# :nocov:
|
26
|
+
loaded_modules = [Implementation]
|
223
27
|
|
224
|
-
|
225
|
-
|
226
|
-
|
28
|
+
if actions.include?(ALL_ACTIONS_ALIAS)
|
29
|
+
loaded_modules += DEPENDENCIES_MAP.values
|
30
|
+
else
|
31
|
+
loaded_modules += actions.map { |action_name| DEPENDENCIES_MAP[action_name] }
|
227
32
|
end
|
228
|
-
# :nocov:
|
229
33
|
|
230
|
-
|
231
|
-
|
232
|
-
raise 'Not Implemented'
|
34
|
+
loaded_modules.uniq.each do |loaded_module|
|
35
|
+
controller_class.include loaded_module
|
233
36
|
end
|
234
|
-
# :nocov:
|
235
|
-
end
|
236
37
|
|
237
|
-
|
238
|
-
|
239
|
-
@resource_class_config
|
38
|
+
HELPER_METHODS.each do |method_name|
|
39
|
+
controller_class.helper_method method_name
|
240
40
|
end
|
241
41
|
|
242
|
-
|
243
|
-
|
244
|
-
end
|
245
|
-
|
246
|
-
def resource_context_config
|
247
|
-
@resource_context_config
|
248
|
-
end
|
249
|
-
|
250
|
-
def resource_context(*values)
|
251
|
-
@resource_context_config = values
|
252
|
-
end
|
253
|
-
|
254
|
-
def paginate_collection_config
|
255
|
-
@paginate_collection_config
|
256
|
-
end
|
257
|
-
|
258
|
-
def paginate_collection(value)
|
259
|
-
@paginate_collection_config = value
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
class ActionsBuilder
|
264
|
-
DEPENDENCIES_MAP = {
|
265
|
-
index: Index,
|
266
|
-
show: Show,
|
267
|
-
new: New,
|
268
|
-
create: Create,
|
269
|
-
edit: Edit,
|
270
|
-
update: Update,
|
271
|
-
destroy: Destroy
|
272
|
-
}.freeze
|
273
|
-
|
274
|
-
HELPER_METHODS = [:resource, :collection].freeze
|
275
|
-
|
276
|
-
ALL_ACTIONS_ALIAS = :crud
|
277
|
-
|
278
|
-
def self.build(controller_class, actions)
|
279
|
-
unless actions.include?(ALL_ACTIONS_ALIAS)
|
280
|
-
raise 'Unknown action name' unless (actions - DEPENDENCIES_MAP.keys).size.zero?
|
281
|
-
end
|
282
|
-
|
283
|
-
controller_class.extend Accessors
|
284
|
-
|
285
|
-
loaded_modules = [CommonMethods]
|
286
|
-
|
287
|
-
if actions.include?(ALL_ACTIONS_ALIAS)
|
288
|
-
loaded_modules += DEPENDENCIES_MAP.values
|
289
|
-
else
|
290
|
-
loaded_modules += actions.map { |action_name| DEPENDENCIES_MAP[action_name] }
|
291
|
-
end
|
292
|
-
|
293
|
-
loaded_modules.uniq.each do |loaded_module|
|
294
|
-
controller_class.include loaded_module
|
295
|
-
end
|
296
|
-
|
297
|
-
HELPER_METHODS.each do |method_name|
|
298
|
-
controller_class.helper_method method_name
|
299
|
-
end
|
300
|
-
|
301
|
-
controller_class.respond_to :html
|
302
|
-
end
|
42
|
+
controller_class.respond_to :html
|
43
|
+
controller_class.respond_to :json
|
303
44
|
end
|
304
45
|
end
|
305
46
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module SimpleResourceController
|
2
2
|
require 'rails'
|
3
|
+
require_relative './controller/config'
|
3
4
|
|
4
5
|
class Railtie < Rails::Railtie
|
5
6
|
initializer 'insert SimpleResourceController to ActionController' do
|
@@ -13,6 +14,7 @@ module SimpleResourceController
|
|
13
14
|
def self.insert
|
14
15
|
if defined?(::ActionController)
|
15
16
|
::ActionController::Base.extend(Configurator)
|
17
|
+
::ActionController::Base.extend(SimpleResourceController::Controller::Config)
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
@@ -19,11 +19,13 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_development_dependency "bundler"
|
23
|
-
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "bundler"
|
23
|
+
spec.add_development_dependency "rake"
|
24
24
|
spec.add_development_dependency "rspec", "~> 3.0"
|
25
|
+
spec.add_development_dependency "jbuilder"
|
26
|
+
spec.add_development_dependency 'active_model_serializers', '~> 0.10.0'
|
25
27
|
|
26
|
-
spec.add_dependency "railties"
|
27
|
-
spec.add_dependency "actionpack"
|
28
|
-
spec.add_dependency "responders"
|
28
|
+
spec.add_dependency "railties"
|
29
|
+
spec.add_dependency "actionpack"
|
30
|
+
spec.add_dependency "responders"
|
29
31
|
end
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_resource_controller
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg Zaporozhchenko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,48 +52,76 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: jbuilder
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: active_model_serializers
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.10.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.10.0
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: railties
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
58
86
|
requirements:
|
59
87
|
- - ">="
|
60
88
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
89
|
+
version: '0'
|
62
90
|
type: :runtime
|
63
91
|
prerelease: false
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
65
93
|
requirements:
|
66
94
|
- - ">="
|
67
95
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
96
|
+
version: '0'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: actionpack
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
72
100
|
requirements:
|
73
101
|
- - ">="
|
74
102
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
103
|
+
version: '0'
|
76
104
|
type: :runtime
|
77
105
|
prerelease: false
|
78
106
|
version_requirements: !ruby/object:Gem::Requirement
|
79
107
|
requirements:
|
80
108
|
- - ">="
|
81
109
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
110
|
+
version: '0'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: responders
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
86
114
|
requirements:
|
87
|
-
- -
|
115
|
+
- - ">="
|
88
116
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
117
|
+
version: '0'
|
90
118
|
type: :runtime
|
91
119
|
prerelease: false
|
92
120
|
version_requirements: !ruby/object:Gem::Requirement
|
93
121
|
requirements:
|
94
|
-
- -
|
122
|
+
- - ">="
|
95
123
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
124
|
+
version: '0'
|
97
125
|
description: This gem allows to write explicit resource controllers
|
98
126
|
email:
|
99
127
|
- c3.gdlk@gmail.com
|
@@ -114,6 +142,11 @@ files:
|
|
114
142
|
- lib/simple_resource_controller.rb
|
115
143
|
- lib/simple_resource_controller/configurator.rb
|
116
144
|
- lib/simple_resource_controller/controller.rb
|
145
|
+
- lib/simple_resource_controller/controller/actions.rb
|
146
|
+
- lib/simple_resource_controller/controller/config.rb
|
147
|
+
- lib/simple_resource_controller/controller/implementation.rb
|
148
|
+
- lib/simple_resource_controller/controller/implementation/format/api.rb
|
149
|
+
- lib/simple_resource_controller/controller/implementation/format/html.rb
|
117
150
|
- lib/simple_resource_controller/railtie.rb
|
118
151
|
- lib/simple_resource_controller/version.rb
|
119
152
|
- simple_resource_controller.gemspec
|
@@ -136,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
169
|
- !ruby/object:Gem::Version
|
137
170
|
version: '0'
|
138
171
|
requirements: []
|
139
|
-
rubygems_version: 3.
|
172
|
+
rubygems_version: 3.1.2
|
140
173
|
signing_key:
|
141
174
|
specification_version: 4
|
142
175
|
summary: Simple gem for resource controllers
|