effective_resources 0.7.13 → 0.8.0
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/app/controllers/concerns/effective/crud_controller.rb +78 -93
- data/app/helpers/effective_resources_helper.rb +5 -59
- data/app/models/effective/resources/actions.rb +21 -4
- data/app/models/effective/resources/forms.rb +54 -0
- data/lib/effective_resources/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 548398bd2a4c2d0b765dbe366a13792a40e2738b
|
4
|
+
data.tar.gz: 0c86f9d641ce9453397ae1f85b9601f0995f45d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d8512be42bc14efb7cbd3683ed59e5a0b8a9f5c8735c9b54c0b2864f6ea4a7932e150f861eac0371cb06e7a3c0b785b46bac565fc69349b23eb6ee11f38fded
|
7
|
+
data.tar.gz: 972f967e8097e08411b32f544bda79e8fdb35508a1cb48112066769a92a5084235c5d859ac2d3113b98c60820048d11c978b7abb34d3c44191227ad8b532d887
|
@@ -4,28 +4,29 @@ module Effective
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
class << self
|
7
|
-
|
8
|
-
|
7
|
+
|
8
|
+
def effective_resource
|
9
|
+
@_effective_resource ||= Effective::Resource.new(controller_path)
|
9
10
|
end
|
10
11
|
|
11
|
-
def
|
12
|
-
|
13
|
-
{ 'Save': { action: :save }, 'Continue': { action: :save }, 'Add New': { action: :save } }
|
14
|
-
else
|
15
|
-
{
|
16
|
-
'Save' => { action: :save, data: { disable_with: 'Saving...' }},
|
17
|
-
'Continue' => { action: :save, data: { disable_with: 'Saving...' }},
|
18
|
-
'Add New' => { action: :save, data: { disable_with: 'Saving...' }}
|
19
|
-
}
|
20
|
-
end
|
12
|
+
def submits
|
13
|
+
effective_resource.submits
|
21
14
|
end
|
22
15
|
end
|
23
16
|
|
17
|
+
define_actions_from_routes
|
24
18
|
define_callbacks :resource_render, :resource_save, :resource_error
|
25
19
|
end
|
26
20
|
|
27
21
|
module ClassMethods
|
28
22
|
|
23
|
+
# Automatically respond to any action defined via the routes file
|
24
|
+
def define_actions_from_routes
|
25
|
+
resource = Effective::Resource.new(controller_path)
|
26
|
+
resource.member_actions.each { |action| member_action(action) }
|
27
|
+
resource.collection_actions.each { |action| collection_action(action) }
|
28
|
+
end
|
29
|
+
|
29
30
|
# https://github.com/rails/rails/blob/v5.1.4/actionpack/lib/abstract_controller/callbacks.rb
|
30
31
|
def before_render(*names, &blk)
|
31
32
|
_insert_callbacks(names, blk) { |name, options| set_callback(:resource_render, :before, name, options) }
|
@@ -39,73 +40,44 @@ module Effective
|
|
39
40
|
_insert_callbacks(names, blk) { |name, options| set_callback(:resource_error, :after, name, options) }
|
40
41
|
end
|
41
42
|
|
42
|
-
#
|
43
|
-
#
|
43
|
+
# This controls the form submit options of effective_submit
|
44
|
+
# It also controls the redirect path for any actions
|
44
45
|
#
|
45
|
-
#
|
46
|
+
# Effective::Resource will populate this with all member_post_actions
|
47
|
+
# And you can control the details with this DSL:
|
46
48
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# member_action :approve, 'Save and Approve', if: -> { approved? }
|
52
|
-
# member_action :approve, 'Save and Approve', unless: -> { !approved? }, redirect: :show
|
53
|
-
|
54
|
-
def member_action(action, commit = nil, args = {})
|
55
|
-
if commit.present?
|
56
|
-
raise 'expected args to be a Hash or false' unless args.kind_of?(Hash) || args == false
|
57
|
-
|
58
|
-
if args == false
|
59
|
-
member_actions.delete(commit); return
|
60
|
-
end
|
61
|
-
|
62
|
-
if args.key?(:if) && args[:if].respond_to?(:call) == false
|
63
|
-
raise "expected if: to be callable. Try member_action :approve, 'Save and Approve', if: -> { submitted? }"
|
64
|
-
end
|
65
|
-
|
66
|
-
if args.key?(:unless) && args[:unless].respond_to?(:call) == false
|
67
|
-
raise "expected unless: to be callable. Try member_action :approve, 'Save and Approve', unless: -> { declined? }"
|
68
|
-
end
|
49
|
+
# submit :approve, 'Save and Approve', unless: -> { approved? }, redirect: :show
|
50
|
+
#
|
51
|
+
# submit :toggle, 'Blacklist', if: -> { sync? }, class: 'btn btn-primary'
|
52
|
+
# submit :toggle, 'Whitelist', if: -> { !sync? }, class: 'btn btn-primary'
|
69
53
|
|
70
|
-
|
54
|
+
def submit(action, commit = nil, args = {})
|
55
|
+
raise 'expected args to be a Hash or false' unless args.kind_of?(Hash) || args == false
|
71
56
|
|
72
|
-
|
57
|
+
if commit == false
|
58
|
+
submits.delete_if { |commit, args| args[:action] == action }; return
|
73
59
|
end
|
74
60
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
EffectiveResources.authorize!(self, action, resource)
|
79
|
-
|
80
|
-
@page_title ||= "#{action.to_s.titleize} #{resource}"
|
81
|
-
|
82
|
-
member_post_action(action) unless request.get?
|
61
|
+
if args == false
|
62
|
+
submits.delete(commit); return
|
83
63
|
end
|
84
|
-
end
|
85
64
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
self.resources ||= resource_scope.where(id: params[:ids])
|
90
|
-
end
|
91
|
-
|
92
|
-
if effective_resource.scope?(action)
|
93
|
-
self.resources ||= resource_scope.public_send(action)
|
94
|
-
end
|
95
|
-
|
96
|
-
self.resources ||= resource_scope.all
|
97
|
-
|
98
|
-
EffectiveResources.authorize!(self, action, resource_klass)
|
65
|
+
if commit # Overwrite the default member action when given a custom commit
|
66
|
+
submits.delete_if { |commit, args| args[:default] && args[:action] == action }
|
67
|
+
end
|
99
68
|
|
100
|
-
|
69
|
+
if args.key?(:if) && args[:if].respond_to?(:call) == false
|
70
|
+
raise "expected if: to be callable. Try submit :approve, 'Save and Approve', if: -> { finished? }"
|
71
|
+
end
|
101
72
|
|
102
|
-
|
73
|
+
if args.key?(:unless) && args[:unless].respond_to?(:call) == false
|
74
|
+
raise "expected unless: to be callable. Try submit :approve, 'Save and Approve', unless: -> { declined? }"
|
103
75
|
end
|
104
|
-
end
|
105
76
|
|
106
|
-
|
107
|
-
|
108
|
-
|
77
|
+
redirect = args.delete(:redirect_to) || args.delete(:redirect) # Remove redirect_to keyword. use redirect.
|
78
|
+
args.merge!(action: action, redirect: redirect)
|
79
|
+
|
80
|
+
(submits[commit] ||= {}).merge!(args)
|
109
81
|
end
|
110
82
|
|
111
83
|
# page_title 'My Title', only: [:new]
|
@@ -138,6 +110,43 @@ module Effective
|
|
138
110
|
end
|
139
111
|
end
|
140
112
|
|
113
|
+
# Defines a function to handle a GET and POST request on this URL
|
114
|
+
# Just add a member action to your routes, you shouldn't need to call this directly
|
115
|
+
def member_action(action)
|
116
|
+
define_method(action) do
|
117
|
+
self.resource ||= resource_scope.find(params[:id])
|
118
|
+
|
119
|
+
EffectiveResources.authorize!(self, action, resource)
|
120
|
+
|
121
|
+
@page_title ||= "#{action.to_s.titleize} #{resource}"
|
122
|
+
|
123
|
+
member_post_action(action) unless request.get?
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Defines a function to handle a GET and POST request on this URL
|
128
|
+
# Handles bulk_ actions
|
129
|
+
# Just add a member action to your routes, you shouldn't need to call this directly
|
130
|
+
# You shouldn't need to call this directly
|
131
|
+
def collection_action(action)
|
132
|
+
define_method(action) do
|
133
|
+
if params[:ids].present?
|
134
|
+
self.resources ||= resource_scope.where(id: params[:ids])
|
135
|
+
end
|
136
|
+
|
137
|
+
if effective_resource.scope?(action)
|
138
|
+
self.resources ||= resource_scope.public_send(action)
|
139
|
+
end
|
140
|
+
|
141
|
+
self.resources ||= resource_scope.all
|
142
|
+
|
143
|
+
EffectiveResources.authorize!(self, action, resource_klass)
|
144
|
+
|
145
|
+
@page_title ||= "#{action.to_s.titleize} #{resource_plural_name.titleize}"
|
146
|
+
|
147
|
+
collection_post_action(action) unless request.get?
|
148
|
+
end
|
149
|
+
end
|
141
150
|
end
|
142
151
|
|
143
152
|
def index
|
@@ -299,31 +308,6 @@ module Effective
|
|
299
308
|
render json: { status: 200, message: "Successfully #{action_verb(action)} #{successes} / #{resources.length} selected #{resource_plural_name}" }
|
300
309
|
end
|
301
310
|
|
302
|
-
# Here we look at all available (class level) member actions, see which ones apply to the current resource
|
303
|
-
# This feeds into the helper simple_form_submit(f)
|
304
|
-
# Returns a Hash of {'Save': {data-disable-with: 'Saving...'}, 'Approve': {data-disable-with: 'Approve'}}
|
305
|
-
def member_actions_for(obj)
|
306
|
-
actions = (self.class.member_actions.presence || self.class._default_member_actions)
|
307
|
-
|
308
|
-
actions.select do |commit, args|
|
309
|
-
args[:class] = args[:class].to_s
|
310
|
-
|
311
|
-
(args.key?(:if) ? obj.instance_exec(&args[:if]) : true) &&
|
312
|
-
(args.key?(:unless) ? !obj.instance_exec(&args[:unless]) : true)
|
313
|
-
end.sort do |(commit_x, x), (commit_y, y)|
|
314
|
-
# Sort to front
|
315
|
-
primary = (y[:class].include?('primary') ? 1 : 0) - (x[:class].include?('primary') ? 1 : 0)
|
316
|
-
primary = nil if primary == 0
|
317
|
-
|
318
|
-
# Sort to back
|
319
|
-
danger = (x[:class].include?('danger') ? 1 : 0) - (y[:class].include?('danger') ? 1 : 0)
|
320
|
-
danger = nil if danger == 0
|
321
|
-
|
322
|
-
primary || danger || actions.keys.index(commit_x) <=> actions.keys.index(commit_y)
|
323
|
-
end.inject({}) do |h, (commit, args)|
|
324
|
-
h[commit] = args.except(:action, :if, :unless, :redirect); h
|
325
|
-
end
|
326
|
-
end
|
327
311
|
|
328
312
|
protected
|
329
313
|
|
@@ -357,6 +341,7 @@ module Effective
|
|
357
341
|
when :index ; resource_index_path
|
358
342
|
when :edit ; resource_edit_path
|
359
343
|
when :show ; resource_show_path
|
344
|
+
when :new ; resource_new_path
|
360
345
|
when :back ; referer_redirect_path
|
361
346
|
when nil ; nil
|
362
347
|
else ; resource_member_action_path(commit_action[:action])
|
@@ -466,7 +451,7 @@ module Effective
|
|
466
451
|
end
|
467
452
|
|
468
453
|
def commit_action
|
469
|
-
self.class.
|
454
|
+
self.class.submits[params[:commit].to_s] || { action: :save }
|
470
455
|
end
|
471
456
|
|
472
457
|
# Returns an ActiveRecord relation based on the computed value of `resource_scope` dsl method
|
@@ -1,77 +1,23 @@
|
|
1
1
|
module EffectiveResourcesHelper
|
2
2
|
|
3
3
|
def effective_submit(form, options = {}, &block) # effective_bootstrap
|
4
|
-
resource = (
|
5
|
-
|
6
|
-
# Apply btn-primary to the first item, only if the class isn't already present
|
7
|
-
actions = if controller.respond_to?(:member_actions_for)
|
8
|
-
controller.member_actions_for(form.object).transform_values.with_index do |opts, index|
|
9
|
-
opts[:class] = "btn #{index == 0 ? 'btn-primary' : 'btn-secondary'}" if opts[:class].blank?
|
10
|
-
opts
|
11
|
-
end
|
12
|
-
else
|
13
|
-
{}.tap do |actions|
|
14
|
-
actions['Save'] = { class: 'btn btn-primary' }
|
15
|
-
|
16
|
-
if resource.action_path(:index) && EffectiveResources.authorized?(controller, :index, resource.klass)
|
17
|
-
actions['Continue'] = { class: 'btn btn-secondary' }
|
18
|
-
end
|
19
|
-
|
20
|
-
if resource.action_path(:new) && EffectiveResources.authorized?(controller, :new, resource.klass)
|
21
|
-
actions['Add New'] = { class: 'btn btn-secondary' }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
4
|
+
resource = (controller.class.respond_to?(:effective_resource) ? controller.class.effective_resource : Effective::Resource.new(controller_path))
|
5
|
+
actions = resource.submits_for(form.object, controller: controller)
|
25
6
|
|
26
7
|
# Group by class and render
|
27
8
|
buttons = actions.group_by { |_, opts| opts[:class] }.flat_map do |_, btns|
|
28
9
|
btns.map { |name, opts| form.save(name, opts) }
|
29
10
|
end.join.html_safe
|
30
11
|
|
31
|
-
|
12
|
+
form.submit('', options) do
|
32
13
|
(block_given? ? capture(&block) : ''.html_safe) + buttons
|
33
14
|
end
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
def effective_save(form, label = 'Save', &block) # effective_bootstrap
|
38
|
-
wrapper = (form.layout == :horizontal) ? { class: 'form-group form-actions row' } : { class: 'form-group form-actions' }
|
39
|
-
|
40
|
-
content_tag(:div, wrapper) do
|
41
|
-
icon('spinner') + (block_given? ? capture(&block) : form.save(label, class: 'btn btn-primary'))
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def effective_save_button(form, label = 'Save', &block)
|
46
|
-
content_tag(:div, class: 'form-actions') do
|
47
|
-
icon('spinner') + (block_given? ? capture(&block) : form.save(label, class: 'btn btn-primary'))
|
48
|
-
end
|
49
15
|
end
|
50
16
|
|
51
17
|
# effective_form_inputs
|
52
18
|
def simple_form_submit(form, options = {}, &block)
|
53
|
-
resource = (
|
54
|
-
|
55
|
-
# Apply btn-primary to the first item, only if the class isn't already present
|
56
|
-
actions = if controller.respond_to?(:member_actions_for)
|
57
|
-
controller.member_actions_for(form.object).transform_values.with_index do |opts, index|
|
58
|
-
opts[:class] = "btn #{index == 0 ? 'btn-primary' : 'btn-default'}" if opts[:class].blank?
|
59
|
-
opts
|
60
|
-
end
|
61
|
-
else
|
62
|
-
{}.tap do |actions|
|
63
|
-
actions['Save'] = { class: 'btn btn-primary', data: { disable_with: 'Saving...' }}
|
64
|
-
|
65
|
-
if resource.action_path(:index) && EffectiveResources.authorized?(controller, :index, resource.klass)
|
66
|
-
actions['Continue'] = { class: 'btn btn-default', data: { disable_with: 'Saving...' }}
|
67
|
-
end
|
68
|
-
|
69
|
-
if resource.action_path(:new) && EffectiveResources.authorized?(controller, :new, resource.klass)
|
70
|
-
actions['Add New'] = { class: 'btn btn-default', data: { disable_with: 'Saving...' }}
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
19
|
+
resource = (controller.class.respond_to?(:effective_resource) ? controller.class.effective_resource : Effective::Resource.new(controller_path))
|
20
|
+
actions = resource.submits_for(form.object, controller: controller)
|
75
21
|
|
76
22
|
wrapper_options = { class: 'form-actions' }.merge(options.delete(:wrapper_html) || {})
|
77
23
|
|
@@ -54,17 +54,30 @@ module Effective
|
|
54
54
|
|
55
55
|
# GET actions
|
56
56
|
def collection_actions
|
57
|
-
routes.values.map { |route| route.defaults[:action].to_sym if
|
57
|
+
routes.values.map { |route| route.defaults[:action].to_sym if is_collection_route?(route) }.compact - crud_actions
|
58
58
|
end
|
59
59
|
|
60
|
-
|
60
|
+
def collection_get_actions
|
61
|
+
routes.values.map { |route| route.defaults[:action].to_sym if is_collection_route?(route) && is_get_route?(route) }.compact - crud_actions
|
62
|
+
end
|
63
|
+
|
64
|
+
def collection_post_actions
|
65
|
+
routes.values.map { |route| route.defaults[:action].to_sym if is_collection_route?(route) && is_post_route?(route) }.compact - crud_actions
|
66
|
+
end
|
67
|
+
|
68
|
+
# All actions
|
61
69
|
def member_actions
|
62
|
-
routes.values.map { |route| route.defaults[:action].to_sym if
|
70
|
+
routes.values.map { |route| route.defaults[:action].to_sym if is_member_route?(route) }.compact - crud_actions
|
71
|
+
end
|
72
|
+
|
73
|
+
# GET actions
|
74
|
+
def member_get_actions
|
75
|
+
routes.values.map { |route| route.defaults[:action].to_sym if is_member_route?(route) && is_get_route?(route) }.compact - crud_actions
|
63
76
|
end
|
64
77
|
|
65
78
|
# POST/PUT/PATCH actions
|
66
79
|
def member_post_actions
|
67
|
-
routes.values.map { |route| route.defaults[:action].to_sym if
|
80
|
+
routes.values.map { |route| route.defaults[:action].to_sym if is_member_route?(route) && is_post_route?(route) }.compact - crud_actions
|
68
81
|
end
|
69
82
|
|
70
83
|
# Same as controller_path in the view
|
@@ -82,6 +95,10 @@ module Effective
|
|
82
95
|
(route.path.required_names || []).include?('id')
|
83
96
|
end
|
84
97
|
|
98
|
+
def is_collection_route?(route)
|
99
|
+
(route.path.required_names || []).include?('id') == false
|
100
|
+
end
|
101
|
+
|
85
102
|
def is_get_route?(route)
|
86
103
|
route.verb.to_s.include?('GET')
|
87
104
|
end
|
@@ -2,6 +2,60 @@ module Effective
|
|
2
2
|
module Resources
|
3
3
|
module Forms
|
4
4
|
|
5
|
+
# Used by effective_form_submit
|
6
|
+
# The actions we would use to commit. For link_to
|
7
|
+
# { 'Save': { action: :save }, 'Continue': { action: :save }, 'Add New': { action: :save }, 'Approve': { action: :approve } }
|
8
|
+
# Saves a list of commit actions...
|
9
|
+
def submits
|
10
|
+
@submits ||= {}.tap do |submits|
|
11
|
+
if (actions.find { |a| a == :create } || actions.find { |a| a == :update })
|
12
|
+
submits['Save'] = { action: :save, class: 'btn btn-primary' }
|
13
|
+
end
|
14
|
+
|
15
|
+
member_post_actions.each do |action| # default true means it will be overwritten by dsl methods
|
16
|
+
submits[action.to_s.titleize] = { action: action, default: true, class: 'btn btn-primary' }
|
17
|
+
end
|
18
|
+
|
19
|
+
if actions.find { |a| a == :index }
|
20
|
+
submits['Continue'] = { action: :save, redirect: :index }
|
21
|
+
end
|
22
|
+
|
23
|
+
if actions.find { |a| a == :new }
|
24
|
+
submits['Add New'] = { action: :save, redirect: :new }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Here we look at all available (class level) member actions, see which ones apply to the current resource
|
30
|
+
# This feeds into the helper simple_form_submit(f)
|
31
|
+
# Returns a Hash of {'Save': {data-disable-with: 'Saving...'}, 'Approve': {data-disable-with: 'Approve'}}
|
32
|
+
def submits_for(obj, controller:)
|
33
|
+
submits.select do |commit, args|
|
34
|
+
args[:class] = args[:class].to_s
|
35
|
+
|
36
|
+
action = (args[:action] == :save ? (obj.new_record? ? :create : :update) : args[:action])
|
37
|
+
|
38
|
+
(args.key?(:if) ? obj.instance_exec(&args[:if]) : true) &&
|
39
|
+
(args.key?(:unless) ? !obj.instance_exec(&args[:unless]) : true) &&
|
40
|
+
EffectiveResources.authorized?(controller, action, obj)
|
41
|
+
end.sort do |(commit_x, x), (commit_y, y)|
|
42
|
+
# Sort to front
|
43
|
+
primary = (y[:class].include?('primary') ? 1 : 0) - (x[:class].include?('primary') ? 1 : 0)
|
44
|
+
primary = nil if primary == 0
|
45
|
+
|
46
|
+
# Sort to back
|
47
|
+
danger = (x[:class].include?('danger') ? 1 : 0) - (y[:class].include?('danger') ? 1 : 0)
|
48
|
+
danger = nil if danger == 0
|
49
|
+
|
50
|
+
primary || danger || submits.keys.index(commit_x) <=> submits.keys.index(commit_y)
|
51
|
+
end.inject({}) do |h, (commit, args)|
|
52
|
+
h[commit] = args.except(:action, :default, :if, :unless, :redirect); h
|
53
|
+
end.transform_values.with_index do |opts, index|
|
54
|
+
opts[:class] = "btn #{index == 0 ? 'btn-primary' : 'btn-secondary'}" if opts[:class].blank?
|
55
|
+
opts
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
5
59
|
# Used by datatables
|
6
60
|
def search_form_field(name, type = nil)
|
7
61
|
case (type || sql_type(name))
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_resources
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|