effective_resources 0.9.5 → 0.10.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 +23 -546
- data/app/controllers/concerns/effective/crud_controller/actions.rb +289 -0
- data/app/controllers/concerns/effective/crud_controller/dsl.rb +81 -0
- data/app/controllers/concerns/effective/crud_controller/paths.rb +87 -0
- data/app/controllers/concerns/effective/crud_controller/permitted_params.rb +66 -0
- data/app/controllers/concerns/effective/crud_controller/save.rb +77 -0
- data/app/controllers/concerns/effective/crud_controller/submits.rb +122 -0
- data/app/helpers/effective_resources_helper.rb +51 -52
- data/app/helpers/effective_resources_private_helper.rb +69 -0
- data/app/models/concerns/effective_resource.rb +24 -0
- data/app/models/effective/model_reader.rb +29 -0
- data/app/models/effective/resource.rb +6 -2
- data/app/models/effective/resources/actions.rb +10 -10
- data/app/models/effective/resources/associations.rb +5 -0
- data/app/models/effective/resources/attributes.rb +40 -27
- data/app/models/effective/resources/controller.rb +81 -0
- data/app/models/effective/resources/forms.rb +0 -51
- data/app/models/effective/resources/init.rb +19 -17
- data/app/models/effective/resources/klass.rb +6 -8
- data/app/models/effective/resources/model.rb +23 -0
- data/app/models/effective/resources/naming.rb +7 -3
- data/app/models/effective/resources/paths.rb +4 -63
- data/app/models/effective/resources/relation.rb +4 -1
- data/app/models/effective/resources/sql.rb +1 -1
- data/app/views/application/create.js.erb +1 -1
- data/app/views/application/edit.html.haml +2 -2
- data/app/views/application/index.html.haml +1 -1
- data/app/views/application/member_action.js.erb +1 -1
- data/app/views/application/new.html.haml +3 -1
- data/app/views/application/show.html.haml +1 -1
- data/app/views/application/update.js.erb +1 -1
- data/app/views/effective/resource/_actions.html.haml +3 -32
- data/app/views/effective/resource/_actions_dropleft.html.haml +4 -26
- data/app/views/effective/resource/_actions_glyphicons.html.haml +4 -10
- data/lib/effective_resources/engine.rb +1 -0
- data/lib/effective_resources/version.rb +1 -1
- metadata +14 -3
@@ -0,0 +1,289 @@
|
|
1
|
+
module Effective
|
2
|
+
module CrudController
|
3
|
+
module Actions
|
4
|
+
|
5
|
+
def index
|
6
|
+
Rails.logger.info 'Processed by Effective::CrudController#index'
|
7
|
+
|
8
|
+
EffectiveResources.authorize!(self, :index, resource_klass)
|
9
|
+
@page_title ||= resource_plural_name.titleize
|
10
|
+
|
11
|
+
self.resources ||= resource_scope.all
|
12
|
+
|
13
|
+
if (datatable = resource_datatable_class).present?
|
14
|
+
@datatable ||= datatable.new(resource_datatable_attributes)
|
15
|
+
@datatable.view = view_context
|
16
|
+
end
|
17
|
+
|
18
|
+
run_callbacks(:resource_render)
|
19
|
+
end
|
20
|
+
|
21
|
+
def new
|
22
|
+
Rails.logger.info 'Processed by Effective::CrudController#new'
|
23
|
+
|
24
|
+
self.resource ||= resource_scope.new
|
25
|
+
|
26
|
+
self.resource.assign_attributes(
|
27
|
+
params.to_unsafe_h.except(:controller, :action, :id).select { |k, v| resource.respond_to?("#{k}=") }
|
28
|
+
)
|
29
|
+
|
30
|
+
if params[:duplicate_id]
|
31
|
+
duplicate = resource_scope.find(params[:duplicate_id])
|
32
|
+
EffectiveResources.authorize!(self, :show, duplicate)
|
33
|
+
|
34
|
+
self.resource = duplicate_resource(duplicate)
|
35
|
+
raise "expected duplicate_resource to return an unsaved new #{resource_klass} resource" unless resource.kind_of?(resource_klass) && resource.new_record?
|
36
|
+
|
37
|
+
if (message = flash[:success].to_s).present?
|
38
|
+
flash.delete(:success)
|
39
|
+
flash.now[:success] = "#{message.chomp('.')}. Adding another #{resource_name.titleize} based on previous."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
EffectiveResources.authorize!(self, :new, resource)
|
44
|
+
@page_title ||= "New #{resource_name.titleize}"
|
45
|
+
|
46
|
+
run_callbacks(:resource_render)
|
47
|
+
end
|
48
|
+
|
49
|
+
def create
|
50
|
+
Rails.logger.info 'Processed by Effective::CrudController#create'
|
51
|
+
|
52
|
+
self.resource ||= resource_scope.new
|
53
|
+
action = commit_action[:action]
|
54
|
+
|
55
|
+
resource.assign_attributes(send(resource_params_method_name))
|
56
|
+
resource.created_by = current_user if resource.respond_to?(:created_by=)
|
57
|
+
|
58
|
+
EffectiveResources.authorize!(self, (action == :save ? :create : action), resource)
|
59
|
+
@page_title ||= "New #{resource_name.titleize}"
|
60
|
+
|
61
|
+
respond_to do |format|
|
62
|
+
if save_resource(resource, action)
|
63
|
+
request.format = :html if specific_redirect_path?
|
64
|
+
|
65
|
+
format.html do
|
66
|
+
flash[:success] ||= resource_flash(:success, resource, action)
|
67
|
+
redirect_to(resource_redirect_path)
|
68
|
+
end
|
69
|
+
|
70
|
+
format.js do
|
71
|
+
flash.now[:success] ||= resource_flash(:success, resource, action)
|
72
|
+
reload_resource # create.js.erb
|
73
|
+
end
|
74
|
+
else
|
75
|
+
flash.delete(:success)
|
76
|
+
flash.now[:danger] ||= resource_flash(:danger, resource, action)
|
77
|
+
|
78
|
+
run_callbacks(:resource_render)
|
79
|
+
|
80
|
+
format.html { render :new }
|
81
|
+
format.js {} # create.js.erb
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def show
|
87
|
+
Rails.logger.info 'Processed by Effective::CrudController#show'
|
88
|
+
|
89
|
+
self.resource ||= resource_scope.find(params[:id])
|
90
|
+
|
91
|
+
EffectiveResources.authorize!(self, :show, resource)
|
92
|
+
@page_title ||= resource.to_s
|
93
|
+
|
94
|
+
run_callbacks(:resource_render)
|
95
|
+
end
|
96
|
+
|
97
|
+
def edit
|
98
|
+
Rails.logger.info 'Processed by Effective::CrudController#edit'
|
99
|
+
|
100
|
+
self.resource ||= resource_scope.find(params[:id])
|
101
|
+
|
102
|
+
EffectiveResources.authorize!(self, :edit, resource)
|
103
|
+
@page_title ||= "Edit #{resource}"
|
104
|
+
|
105
|
+
run_callbacks(:resource_render)
|
106
|
+
end
|
107
|
+
|
108
|
+
def update
|
109
|
+
Rails.logger.info 'Processed by Effective::CrudController#update'
|
110
|
+
|
111
|
+
self.resource ||= resource_scope.find(params[:id])
|
112
|
+
action = commit_action[:action]
|
113
|
+
|
114
|
+
EffectiveResources.authorize!(self, (action == :save ? :update : action), resource)
|
115
|
+
@page_title ||= "Edit #{resource}"
|
116
|
+
|
117
|
+
resource.assign_attributes(send(resource_params_method_name))
|
118
|
+
resource.current_user = current_user if resource.respond_to?(:current_user=)
|
119
|
+
|
120
|
+
respond_to do |format|
|
121
|
+
if save_resource(resource, action)
|
122
|
+
request.format = :html if specific_redirect_path?
|
123
|
+
|
124
|
+
format.html do
|
125
|
+
flash[:success] ||= resource_flash(:success, resource, action)
|
126
|
+
redirect_to(resource_redirect_path)
|
127
|
+
end
|
128
|
+
|
129
|
+
format.js do
|
130
|
+
flash.now[:success] ||= resource_flash(:success, resource, action)
|
131
|
+
reload_resource # update.js.erb
|
132
|
+
end
|
133
|
+
else
|
134
|
+
flash.delete(:success)
|
135
|
+
flash.now[:danger] ||= resource_flash(:danger, resource, action)
|
136
|
+
|
137
|
+
run_callbacks(:resource_render)
|
138
|
+
|
139
|
+
format.html { render :edit }
|
140
|
+
format.js { } # update.js.erb
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def destroy
|
146
|
+
Rails.logger.info 'Processed by Effective::CrudController#destroy'
|
147
|
+
|
148
|
+
self.resource = resource_scope.find(params[:id])
|
149
|
+
action = :destroy
|
150
|
+
|
151
|
+
EffectiveResources.authorize!(self, action, resource)
|
152
|
+
@page_title ||= "Destroy #{resource}"
|
153
|
+
|
154
|
+
respond_to do |format|
|
155
|
+
if save_resource(resource, action)
|
156
|
+
request.format = :html if specific_redirect_path?(action)
|
157
|
+
|
158
|
+
format.html do
|
159
|
+
flash[:success] ||= resource_flash(:success, resource, action)
|
160
|
+
redirect_to(resource_redirect_path(action))
|
161
|
+
end
|
162
|
+
|
163
|
+
format.js do
|
164
|
+
flash.now[:success] ||= resource_flash(:success, resource, action)
|
165
|
+
# destroy.js.erb
|
166
|
+
end
|
167
|
+
else
|
168
|
+
flash.delete(:success)
|
169
|
+
request.format = :html # Don't run destroy.js.erb
|
170
|
+
|
171
|
+
format.html do
|
172
|
+
flash[:danger] = (flash.now[:danger].presence || resource_flash(:danger, resource, action))
|
173
|
+
redirect_to(resource_redirect_path(action))
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def member_action(action)
|
180
|
+
Rails.logger.info "Processed by Effective::CrudController#member_action"
|
181
|
+
|
182
|
+
self.resource ||= resource_scope.find(params[:id])
|
183
|
+
|
184
|
+
EffectiveResources.authorize!(self, action, resource)
|
185
|
+
@page_title ||= "#{action.to_s.titleize} #{resource}"
|
186
|
+
|
187
|
+
if request.get?
|
188
|
+
run_callbacks(:resource_render); return
|
189
|
+
end
|
190
|
+
|
191
|
+
to_assign = (send(resource_params_method_name) rescue {})
|
192
|
+
resource.assign_attributes(to_assign) if to_assign.present? && to_assign.permitted?
|
193
|
+
|
194
|
+
resource.current_user = current_user if resource.respond_to?(:current_user=)
|
195
|
+
|
196
|
+
respond_to do |format|
|
197
|
+
if save_resource(resource, action)
|
198
|
+
request.format = :html if specific_redirect_path?(action)
|
199
|
+
|
200
|
+
format.html do
|
201
|
+
flash[:success] ||= resource_flash(:success, resource, action)
|
202
|
+
redirect_to(resource_redirect_path(action))
|
203
|
+
end
|
204
|
+
|
205
|
+
format.js do
|
206
|
+
flash.now[:success] ||= resource_flash(:success, resource, action)
|
207
|
+
reload_resource
|
208
|
+
render_member_action(action)
|
209
|
+
end
|
210
|
+
else
|
211
|
+
flash.delete(:success)
|
212
|
+
flash.now[:danger] ||= resource_flash(:danger, resource, action)
|
213
|
+
|
214
|
+
run_callbacks(:resource_render)
|
215
|
+
|
216
|
+
format.html do
|
217
|
+
if resource_edit_path && (referer_redirect_path || '').end_with?(resource_edit_path)
|
218
|
+
@page_title ||= "Edit #{resource}"
|
219
|
+
render :edit
|
220
|
+
elsif resource_new_path && (referer_redirect_path || '').end_with?(resource_new_path)
|
221
|
+
@page_title ||= "New #{resource_name.titleize}"
|
222
|
+
render :new
|
223
|
+
elsif resource_show_path && (referer_redirect_path || '').end_with?(resource_show_path)
|
224
|
+
@page_title ||= resource_name.titleize
|
225
|
+
render :show
|
226
|
+
else
|
227
|
+
@page_title ||= resource.to_s
|
228
|
+
flash[:danger] = flash.now[:danger]
|
229
|
+
redirect_to(referer_redirect_path || resource_redirect_path(action))
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
format.js { render_member_action(action) }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def collection_action(action)
|
239
|
+
Rails.logger.info 'Processed by Effective::CrudController#collection_action'
|
240
|
+
|
241
|
+
action = action.to_s.gsub('bulk_', '').to_sym
|
242
|
+
|
243
|
+
if params[:ids].present?
|
244
|
+
self.resources ||= resource_scope.where(id: params[:ids])
|
245
|
+
end
|
246
|
+
|
247
|
+
if effective_resource.scope?(action)
|
248
|
+
self.resources ||= resource_scope.public_send(action)
|
249
|
+
end
|
250
|
+
|
251
|
+
self.resources ||= resource_scope.all
|
252
|
+
|
253
|
+
EffectiveResources.authorize!(self, action, resource_klass)
|
254
|
+
@page_title ||= "#{action.to_s.titleize} #{resource_plural_name.titleize}"
|
255
|
+
|
256
|
+
if request.get?
|
257
|
+
run_callbacks(:resource_render); return
|
258
|
+
end
|
259
|
+
|
260
|
+
raise "expected all #{resource_name} objects to respond to #{action}!" if resources.to_a.present? && !resources.all? { |resource| resource.respond_to?("#{action}!") }
|
261
|
+
|
262
|
+
successes = 0
|
263
|
+
|
264
|
+
# No attributes are assigned or saved. We purely call action! on the resource
|
265
|
+
|
266
|
+
ActiveRecord::Base.transaction do
|
267
|
+
successes = resources.select do |resource|
|
268
|
+
begin
|
269
|
+
resource.public_send("#{action}!") if EffectiveResources.authorized?(self, action, resource)
|
270
|
+
rescue => e
|
271
|
+
false
|
272
|
+
end
|
273
|
+
end.length
|
274
|
+
end
|
275
|
+
|
276
|
+
render json: { status: 200, message: "Successfully #{action_verb(action)} #{successes} / #{resources.length} selected #{resource_plural_name}" }
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
private
|
281
|
+
|
282
|
+
# Which member javascript view to render: #{action}.js or effective_resources member_action.js
|
283
|
+
def render_member_action(action)
|
284
|
+
view = lookup_context.template_exists?(action, _prefixes) ? action : :member_action
|
285
|
+
render(view, locals: { action: action })
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Effective
|
2
|
+
module CrudController
|
3
|
+
module Dsl
|
4
|
+
|
5
|
+
# https://github.com/rails/rails/blob/v5.1.4/actionpack/lib/abstract_controller/callbacks.rb
|
6
|
+
def before_render(*names, &blk)
|
7
|
+
_insert_callbacks(names, blk) { |name, options| set_callback(:resource_render, :before, name, options) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def after_save(*names, &blk)
|
11
|
+
_insert_callbacks(names, blk) { |name, options| set_callback(:resource_save, :after, name, options) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def after_error(*names, &blk)
|
15
|
+
_insert_callbacks(names, blk) { |name, options| set_callback(:resource_error, :after, name, options) }
|
16
|
+
end
|
17
|
+
|
18
|
+
# This controls the form submit options of effective_submit
|
19
|
+
# Takes precidence over any 'on' dsl commands
|
20
|
+
#
|
21
|
+
# Effective::Resource will populate this with all crud actions
|
22
|
+
# And you can control the details with this DSL:
|
23
|
+
#
|
24
|
+
# submit :approve, 'Save and Approve', unless: -> { resource.approved? }, redirect: :show
|
25
|
+
#
|
26
|
+
# submit :toggle, 'Blacklist', if: -> { sync? }, class: 'btn btn-primary'
|
27
|
+
# submit :toggle, 'Whitelist', if: -> { !sync? }, class: 'btn btn-primary'
|
28
|
+
# submit :save, 'Save', success: -> { "#{resource} was saved okay!" }
|
29
|
+
def submit(action, label = nil, args = {})
|
30
|
+
_insert_submit(action, label, args)
|
31
|
+
end
|
32
|
+
|
33
|
+
# This controls the resource buttons section of the page
|
34
|
+
# Takes precidence over any on commands
|
35
|
+
#
|
36
|
+
# Effective::Resource will populate this with all member_actions
|
37
|
+
#
|
38
|
+
# button :approve, 'Approve', unless: -> { resource.approved? }, redirect: :show
|
39
|
+
# button :decline, false
|
40
|
+
def button(action, label = nil, args = {})
|
41
|
+
_insert_button(action, label, args)
|
42
|
+
end
|
43
|
+
|
44
|
+
# This is a way of defining the redirect, flash etc of any action without tweaking defaults
|
45
|
+
# submit and buttons options will be merged ontop of these
|
46
|
+
def on(action, args = {})
|
47
|
+
_insert_on(action, args)
|
48
|
+
end
|
49
|
+
|
50
|
+
# page_title 'My Title', only: [:new]
|
51
|
+
def page_title(label = nil, opts = {}, &block)
|
52
|
+
opts = label if label.kind_of?(Hash)
|
53
|
+
raise 'expected a label or block' unless (label || block_given?)
|
54
|
+
|
55
|
+
instance_exec do
|
56
|
+
before_action(opts) { @page_title ||= (block_given? ? instance_exec(&block) : label).to_s }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# resource_scope -> { current_user.things }
|
61
|
+
# resource_scope -> { Thing.active.where(user: current_user) }
|
62
|
+
# resource_scope do
|
63
|
+
# { user_id: current_user.id }
|
64
|
+
# end
|
65
|
+
# Nested controllers? sure
|
66
|
+
# resource_scope -> { User.find(params[:user_id]).things }
|
67
|
+
|
68
|
+
# Return value should be:
|
69
|
+
# a Relation: Thing.where(user: current_user)
|
70
|
+
# a Hash: { user_id: current_user.id }
|
71
|
+
def resource_scope(obj = nil, opts = {}, &block)
|
72
|
+
raise 'expected a proc or block' unless (obj.respond_to?(:call) || block_given?)
|
73
|
+
|
74
|
+
instance_exec do
|
75
|
+
before_action(opts) { @_effective_resource_scope ||= instance_exec(&(block_given? ? block : obj)) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Effective
|
2
|
+
module CrudController
|
3
|
+
module Paths
|
4
|
+
|
5
|
+
def resource_redirect_path(action = nil)
|
6
|
+
submit = commit_action(action)
|
7
|
+
redirect = submit[:redirect].respond_to?(:call) ? instance_exec(&submit[:redirect]) : submit[:redirect]
|
8
|
+
|
9
|
+
commit_action_redirect = case redirect
|
10
|
+
when :index ; resource_index_path
|
11
|
+
when :edit ; resource_edit_path
|
12
|
+
when :show ; resource_show_path
|
13
|
+
when :new ; resource_new_path
|
14
|
+
when :duplicate ; resource_duplicate_path
|
15
|
+
when :back ; referer_redirect_path
|
16
|
+
when :save ; [resource_edit_path, resource_show_path].compact.first
|
17
|
+
when Symbol ; resource_action_path(submit[:action])
|
18
|
+
when String ; redirect
|
19
|
+
else ; nil
|
20
|
+
end
|
21
|
+
|
22
|
+
return commit_action_redirect if commit_action_redirect.present?
|
23
|
+
|
24
|
+
if action == :destroy
|
25
|
+
return [referer_redirect_path, resource_index_path, root_path].compact.first
|
26
|
+
end
|
27
|
+
|
28
|
+
case params[:commit].to_s
|
29
|
+
when 'Save'
|
30
|
+
[resource_edit_path, resource_show_path, resource_index_path]
|
31
|
+
when 'Save and Add New', 'Add New'
|
32
|
+
[resource_new_path, resource_index_path]
|
33
|
+
when 'Duplicate'
|
34
|
+
[resource_duplicate_path, resource_index_path]
|
35
|
+
when 'Continue', 'Save and Continue'
|
36
|
+
[resource_index_path]
|
37
|
+
else
|
38
|
+
[referer_redirect_path, resource_edit_path, resource_show_path, resource_index_path]
|
39
|
+
end.compact.first.presence || root_path
|
40
|
+
end
|
41
|
+
|
42
|
+
def referer_redirect_path
|
43
|
+
url = request.referer.to_s
|
44
|
+
|
45
|
+
return if (resource && resource.respond_to?(:destroyed?) && resource.destroyed? && url.include?("/#{resource.to_param}"))
|
46
|
+
return if url.include?('duplicate_id=')
|
47
|
+
return unless (Rails.application.routes.recognize_path(URI(url).path) rescue false)
|
48
|
+
|
49
|
+
url
|
50
|
+
end
|
51
|
+
|
52
|
+
def specific_redirect_path?(action = nil)
|
53
|
+
submit = commit_action(action)
|
54
|
+
(submit[:redirect].respond_to?(:call) ? instance_exec(&submit[:redirect]) : submit[:redirect]).present?
|
55
|
+
end
|
56
|
+
|
57
|
+
def resource_index_path
|
58
|
+
effective_resource.action_path(:index)
|
59
|
+
end
|
60
|
+
|
61
|
+
def resource_new_path
|
62
|
+
effective_resource.action_path(:new)
|
63
|
+
end
|
64
|
+
|
65
|
+
def resource_duplicate_path
|
66
|
+
effective_resource.action_path(:new, duplicate_id: resource.id)
|
67
|
+
end
|
68
|
+
|
69
|
+
def resource_edit_path
|
70
|
+
effective_resource.action_path(:edit, resource)
|
71
|
+
end
|
72
|
+
|
73
|
+
def resource_show_path
|
74
|
+
effective_resource.action_path(:show, resource)
|
75
|
+
end
|
76
|
+
|
77
|
+
def resource_destroy_path
|
78
|
+
effective_resource.action_path(:destroy, resource)
|
79
|
+
end
|
80
|
+
|
81
|
+
def resource_action_path(action)
|
82
|
+
effective_resource.action_path(action.to_sym, resource)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|