effective_resources 1.5.1 → 1.6.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/README.md +9 -2
- data/app/controllers/concerns/effective/crud_controller.rb +3 -1
- data/app/controllers/concerns/effective/crud_controller/dsl.rb +1 -1
- data/app/controllers/concerns/effective/crud_controller/permitted_params.rb +8 -8
- data/app/controllers/concerns/effective/crud_controller/respond.rb +5 -1
- data/app/helpers/effective_resources_helper.rb +17 -8
- data/app/helpers/effective_resources_private_helper.rb +25 -19
- data/app/models/effective/attribute.rb +3 -0
- data/app/models/effective/model_reader.rb +4 -1
- data/app/models/effective/resources/actions.rb +83 -39
- data/app/models/effective/resources/controller.rb +27 -15
- data/app/models/effective/resources/init.rb +44 -43
- data/app/models/effective/resources/klass.rb +3 -0
- data/app/models/effective/resources/naming.rb +4 -0
- data/app/models/effective/resources/relation.rb +6 -0
- data/app/views/effective/resource/_actions.html.haml +2 -1
- data/app/views/effective/resource/_actions_dropleft.html.haml +4 -1
- data/app/views/effective/resource/_actions_glyphicons.html.haml +4 -1
- data/lib/effective_resources.rb +1 -0
- data/lib/effective_resources/version.rb +1 -1
- metadata +73 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2318bd8d0a93c63c8287583dd80a6b6e067bb5677f330b930d58588677d2cb55
|
4
|
+
data.tar.gz: 82af0a3fdbb5c27bd2498bf82017c398485b755d729674e8963796b5b72f85c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bd4c614b11beea8c848996a541b2e729092164543d9b69727ae346b6146783b0024c8ebeb428615c5806c87107146b10a7055800cf7ad0a7f42a80fea0f54bf
|
7
|
+
data.tar.gz: d942166674ede76968161547a5eef54c1f3e9db015c2878d67ebaaa930117ad53f19beeaeea5632e4d69d39282cadf848c0da5c2cf151b3079d6288d4daeadab
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Effective Resources
|
2
2
|
|
3
3
|
This gem looks at the current `routes.rb`, authorization `ability.rb`, `current_user` and controller context
|
4
|
-
to metaprogram an effective CRUD website.
|
4
|
+
to metaprogram an effective CRUD website.
|
5
5
|
|
6
6
|
It automates linking to resource edit, show, delete pages, as well as member and collection actions.
|
7
7
|
|
@@ -256,6 +256,14 @@ end
|
|
256
256
|
|
257
257
|
and include Effective::CrudController in your resource controller.
|
258
258
|
|
259
|
+
## Testing
|
260
|
+
|
261
|
+
Run tests by:
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
rails test
|
265
|
+
```
|
266
|
+
|
259
267
|
## License
|
260
268
|
|
261
269
|
MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
|
@@ -268,4 +276,3 @@ MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
|
|
268
276
|
4. Push to the branch (`git push origin my-new-feature`)
|
269
277
|
5. Bonus points for test coverage
|
270
278
|
6. Create new Pull Request
|
271
|
-
|
@@ -118,7 +118,9 @@ module Effective
|
|
118
118
|
|
119
119
|
return unless datatable_klass.present?
|
120
120
|
|
121
|
-
datatable_klass.new(resource_datatable_attributes)
|
121
|
+
datatable = datatable_klass.new(resource_datatable_attributes)
|
122
|
+
datatable.effective_resource = effective_resource if datatable.respond_to?(:effective_resource=)
|
123
|
+
datatable
|
122
124
|
end
|
123
125
|
|
124
126
|
def resource_params_method_name
|
@@ -80,7 +80,7 @@ module Effective
|
|
80
80
|
raise 'expected a proc or block' unless (obj.respond_to?(:call) || block_given?)
|
81
81
|
|
82
82
|
instance_exec do
|
83
|
-
|
83
|
+
before_action(opts) { @_effective_resource_scope ||= instance_exec(&(block_given? ? block : obj)) }
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -5,7 +5,7 @@ module Effective
|
|
5
5
|
|
6
6
|
# This is only available to models that use the effective_resource do ... end attributes block
|
7
7
|
# It will be called last, and only for those resources
|
8
|
-
# params.require(effective_resource.
|
8
|
+
# params.require(effective_resource.resource_name).permit!
|
9
9
|
def resource_permitted_params
|
10
10
|
raise 'expected resource class to have effective_resource do .. end' if effective_resource.model.blank?
|
11
11
|
|
@@ -13,10 +13,10 @@ module Effective
|
|
13
13
|
|
14
14
|
if Rails.env.development?
|
15
15
|
Rails.logger.info "Effective::CrudController#resource_permitted_params:"
|
16
|
-
Rails.logger.info "params.require(:#{effective_resource.
|
16
|
+
Rails.logger.info "params.require(:#{effective_resource.resource_name}).permit(#{permitted_params.to_s[1...-1]})"
|
17
17
|
end
|
18
18
|
|
19
|
-
params.require(effective_resource.
|
19
|
+
params.require(effective_resource.resource_name).permit(*permitted_params)
|
20
20
|
end
|
21
21
|
|
22
22
|
# If the resource is ActiveModel, just permit all
|
@@ -24,13 +24,13 @@ module Effective
|
|
24
24
|
def resource_active_model_permitted_params
|
25
25
|
if Rails.env.development?
|
26
26
|
Rails.logger.info "Effective::CrudController#resource_permitted_params:"
|
27
|
-
Rails.logger.info "params.require(:#{effective_resource.
|
27
|
+
Rails.logger.info "params.require(:#{effective_resource.resource_name}).permit!"
|
28
28
|
end
|
29
29
|
|
30
|
-
if params[effective_resource.
|
31
|
-
params.require(effective_resource.
|
30
|
+
if params[effective_resource.resource_name].present?
|
31
|
+
params.require(effective_resource.resource_name).permit!
|
32
32
|
else
|
33
|
-
params.require((effective_resource.namespaces + [effective_resource.
|
33
|
+
params.require((effective_resource.namespaces + [effective_resource.resource_name]).join('_')).permit!
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -96,7 +96,7 @@ module Effective
|
|
96
96
|
|
97
97
|
if (nested_params = permitted_params_for(nested.klass, namespaces)).present?
|
98
98
|
nested_params.insert(nested_params.rindex { |obj| !obj.kind_of?(Hash)} + 1, :_destroy)
|
99
|
-
permitted_params << { "#{nested.
|
99
|
+
permitted_params << { "#{nested.resource_name}_attributes".to_sym => nested_params }
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -64,10 +64,14 @@ module Effective
|
|
64
64
|
else
|
65
65
|
if template_present?(action)
|
66
66
|
format.html { render(action, locals: { action: action }) }
|
67
|
+
elsif request.referer.to_s.end_with?('/edit')
|
68
|
+
format.html { render :edit }
|
69
|
+
elsif request.referer.to_s.end_with?('/new')
|
70
|
+
format.html { render :new }
|
67
71
|
else
|
68
72
|
format.html do
|
69
73
|
redirect_flash
|
70
|
-
redirect_to(
|
74
|
+
redirect_to(resource_redirect_path(action))
|
71
75
|
end
|
72
76
|
end
|
73
77
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module EffectiveResourcesHelper
|
2
4
|
|
3
5
|
# effective_bootstrap
|
@@ -74,18 +76,22 @@ module EffectiveResourcesHelper
|
|
74
76
|
namespace ||= (effective_resource.namespace.to_sym if effective_resource.namespace)
|
75
77
|
|
76
78
|
# Assign actions
|
77
|
-
|
78
|
-
|
79
|
-
|
79
|
+
# We filter out any actions passed to us that aren't supported
|
80
|
+
actions = if atts.key?(:actions)
|
81
|
+
{}.tap do |actions|
|
82
|
+
atts[:actions].each do |commit, opts|
|
83
|
+
actions[commit] = opts if (effective_resource.actions.include?(opts[:action]) || opts[:path]).present?
|
84
|
+
end
|
85
|
+
end
|
80
86
|
else
|
81
87
|
(resource.kind_of?(Class) ? effective_resource.resource_klass_actions : effective_resource.resource_actions)
|
82
88
|
end
|
83
89
|
|
84
90
|
# Consider only, except, false and proc false
|
85
|
-
only = Array(atts[:only]).
|
86
|
-
except = Array(atts[:except]).
|
91
|
+
only = Array(atts[:only]) if atts[:only].present?
|
92
|
+
except = Array(atts[:except]) if atts[:except].present?
|
87
93
|
|
88
|
-
actions
|
94
|
+
actions.select! do |_, opts|
|
89
95
|
action = opts[:action]
|
90
96
|
|
91
97
|
if only.present? && !only.include?(action)
|
@@ -100,8 +106,11 @@ module EffectiveResourcesHelper
|
|
100
106
|
end
|
101
107
|
|
102
108
|
# Select Partial
|
103
|
-
partial =
|
104
|
-
|
109
|
+
partial = if partial.kind_of?(Symbol)
|
110
|
+
"effective/resource/actions_#{partial}.html"
|
111
|
+
else
|
112
|
+
"#{partial.presence || 'effective/resource/actions'}.html"
|
113
|
+
end
|
105
114
|
|
106
115
|
# Assign Locals
|
107
116
|
locals = {
|
@@ -2,21 +2,27 @@
|
|
2
2
|
|
3
3
|
module EffectiveResourcesPrivateHelper
|
4
4
|
REPLACE_PAGE_ACTIONS = {'update' => :edit, 'create' => :new}
|
5
|
+
BLACKLIST = [:default, :only, :except, :if, :unless, :redirect, :success, :danger, :klass]
|
6
|
+
|
7
|
+
DATA_CONFIRM = 'data-confirm'
|
5
8
|
|
6
9
|
def permitted_resource_actions(resource, actions)
|
7
10
|
page_action = REPLACE_PAGE_ACTIONS[params[:action]] || params[:action].try(:to_sym) || :save
|
8
11
|
executor = Effective::ResourceExec.new(self, resource)
|
9
12
|
|
10
|
-
actions.
|
13
|
+
actions.each_with_object({}) do |(commit, args), h|
|
11
14
|
action = (args[:action] == :save ? (resource.new_record? ? :create : :update) : args[:action])
|
12
15
|
|
13
|
-
(args.key?(:only) ? args[:only].include?(page_action) : true) &&
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
permitted = (args.key?(:only) ? args[:only].include?(page_action) : true) &&
|
17
|
+
(args.key?(:except) ? !args[:except].include?(page_action) : true) &&
|
18
|
+
(args.key?(:if) ? executor.instance_exec(&args[:if]) : true) &&
|
19
|
+
(args.key?(:unless) ? !executor.instance_exec(&args[:unless]) : true) &&
|
20
|
+
EffectiveResources.authorized?(controller, action, resource)
|
21
|
+
|
22
|
+
next unless permitted
|
23
|
+
|
19
24
|
opts = args.except(:default, :only, :except, :if, :unless, :redirect, :success, :danger, :klass)
|
25
|
+
resource_to_s = resource.to_s.presence || resource.class.name.underscore
|
20
26
|
|
21
27
|
# Transform data: { ... } hash into 'data-' keys
|
22
28
|
if opts.key?(:data)
|
@@ -32,34 +38,34 @@ module EffectiveResourcesPrivateHelper
|
|
32
38
|
end
|
33
39
|
|
34
40
|
# Replace resource name in any token strings
|
35
|
-
if opts.
|
36
|
-
opts[
|
41
|
+
if opts[DATA_CONFIRM].present? && opts[DATA_CONFIRM].include?('@resource'.freeze)
|
42
|
+
opts[DATA_CONFIRM] = opts[DATA_CONFIRM].gsub('@resource'.freeze, resource_to_s)
|
37
43
|
end
|
38
44
|
|
39
45
|
# Assign class
|
40
46
|
opts[:class] ||= (
|
41
|
-
if opts['data-method']
|
42
|
-
'btn btn-danger'
|
47
|
+
if opts['data-method'.freeze] == 'delete'.freeze
|
48
|
+
'btn btn-danger'.freeze
|
43
49
|
elsif h.length == 0
|
44
|
-
'btn btn-primary'
|
50
|
+
'btn btn-primary'.freeze
|
45
51
|
elsif defined?(EffectiveBootstrap)
|
46
|
-
'btn btn-secondary'
|
52
|
+
'btn btn-secondary'.freeze
|
47
53
|
else
|
48
|
-
'btn btn-default'
|
54
|
+
'btn btn-default'.freeze
|
49
55
|
end
|
50
56
|
)
|
51
57
|
|
52
58
|
# Assign title
|
53
59
|
opts[:title] ||= case opts[:action]
|
54
60
|
when :save then commit
|
55
|
-
when :edit then "Edit #{
|
56
|
-
when :show then "#{
|
57
|
-
when :destroy then "Delete #{
|
61
|
+
when :edit then "Edit #{resource_to_s}"
|
62
|
+
when :show then "#{resource_to_s}"
|
63
|
+
when :destroy then "Delete #{resource_to_s}"
|
58
64
|
when :index then "All #{resource.class.name.gsub('::', ' ').underscore.gsub('_', ' ').titleize.pluralize}"
|
59
|
-
else "#{opts[:action].to_s.titleize} #{
|
65
|
+
else "#{opts[:action].to_s.titleize} #{resource_to_s}"
|
60
66
|
end
|
61
67
|
|
62
|
-
h[commit] = opts
|
68
|
+
h[commit] = opts
|
63
69
|
end
|
64
70
|
end
|
65
71
|
|
@@ -44,6 +44,7 @@ module Effective
|
|
44
44
|
when :string ; :string
|
45
45
|
when :text ; :string
|
46
46
|
when :time ; :time
|
47
|
+
when :uuid ; :uuid
|
47
48
|
when FalseClass ; :boolean
|
48
49
|
when (defined?(Integer) ? Integer : Fixnum) ; :integer
|
49
50
|
when Float ; :decimal
|
@@ -139,6 +140,8 @@ module Effective
|
|
139
140
|
value.to_s
|
140
141
|
end
|
141
142
|
end
|
143
|
+
when :uuid
|
144
|
+
value.to_s
|
142
145
|
when :active_storage
|
143
146
|
value.to_s
|
144
147
|
else
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Effective
|
2
2
|
class ModelReader
|
3
|
-
DATATYPES = [
|
3
|
+
DATATYPES = [
|
4
|
+
:binary, :boolean, :date, :datetime, :decimal, :float, :hstore, :inet, :integer,
|
5
|
+
:string, :text, :uuid, :permitted_param
|
6
|
+
]
|
4
7
|
|
5
8
|
attr_reader :attributes
|
6
9
|
|
@@ -1,41 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Effective
|
2
4
|
module Resources
|
3
5
|
module Actions
|
6
|
+
EMPTY_HASH = {}
|
7
|
+
POST_VERBS = ['POST', 'PUT', 'PATCH']
|
8
|
+
CRUD_ACTIONS = %i(index new create show edit update destroy)
|
4
9
|
|
5
10
|
# This was written for the Edit actions fallback templates and Datatables
|
6
11
|
# Effective::Resource.new('admin/posts').routes[:index]
|
7
12
|
def routes
|
8
13
|
@routes ||= (
|
9
|
-
matches = [
|
14
|
+
matches = [
|
15
|
+
[namespace, plural_name].compact.join('/'),
|
16
|
+
[namespace, name].compact.join('/')
|
17
|
+
]
|
18
|
+
|
19
|
+
# Check main Rails app
|
20
|
+
routes = Rails.application.routes.routes.select do |route|
|
21
|
+
(matches & [route.defaults[:controller]]).present? && !route.name.to_s.end_with?('root')
|
22
|
+
end
|
10
23
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
24
|
+
# Check engine routes
|
25
|
+
if routes.blank?
|
26
|
+
matches = [
|
27
|
+
[namespace, plural_name].compact.join('/'),
|
28
|
+
[namespace, name].compact.join('/'),
|
29
|
+
['effective', namespace, plural_name].compact.join('/'),
|
30
|
+
['effective', namespace, name].compact.join('/')
|
31
|
+
]
|
32
|
+
|
33
|
+
Rails::Engine.subclasses.each do |engine|
|
34
|
+
routes = engine.routes.routes.select do |route|
|
35
|
+
(matches & [route.defaults[:controller]]).present? && !route.name.to_s.end_with?('root')
|
36
|
+
end
|
37
|
+
|
38
|
+
break if routes.present?
|
39
|
+
end
|
15
40
|
end
|
16
|
-
)
|
17
|
-
end
|
18
41
|
|
19
|
-
|
20
|
-
|
21
|
-
case class_name
|
22
|
-
when 'Effective::Order'.freeze
|
23
|
-
EffectiveOrders::Engine
|
24
|
-
else
|
25
|
-
Rails.application
|
26
|
-
end
|
42
|
+
Array(routes).inject({}) { |h, route| h[route.defaults[:action].to_sym] = route; h }
|
43
|
+
)
|
27
44
|
end
|
28
45
|
|
29
46
|
# Effective::Resource.new('admin/posts').action_path_helper(:edit) => 'edit_admin_posts_path'
|
30
47
|
# This will return empty for create, update and destroy
|
31
48
|
def action_path_helper(action)
|
32
49
|
return unless routes[action]
|
33
|
-
return (routes[action].name + '_path'
|
50
|
+
return (routes[action].name + '_path') if routes[action].name.present?
|
34
51
|
end
|
35
52
|
|
36
53
|
# Effective::Resource.new('admin/posts').action_path(:edit, Post.last) => '/admin/posts/3/edit'
|
37
54
|
# Will work for any action. Returns the real path
|
38
|
-
def action_path(action, resource = nil, opts =
|
55
|
+
def action_path(action, resource = nil, opts = nil)
|
56
|
+
opts ||= EMPTY_HASH
|
57
|
+
|
39
58
|
if klass.nil? && resource.present? && initialized_name.kind_of?(ActiveRecord::Reflection::BelongsToReflection)
|
40
59
|
return Effective::Resource.new(resource, namespace: namespace).action_path(action, resource, opts)
|
41
60
|
end
|
@@ -53,12 +72,26 @@ module Effective
|
|
53
72
|
end
|
54
73
|
end
|
55
74
|
|
56
|
-
|
57
|
-
|
58
|
-
|
75
|
+
target = (resource || instance)
|
76
|
+
|
77
|
+
formattable = if routes[action].parts.include?(:id)
|
78
|
+
if target.respond_to?(:to_param) && target.respond_to?(:id) && (target.to_param != target.id.to_s)
|
79
|
+
routes[action].parts.each_with_object({}) do |part, h|
|
80
|
+
if part == :id
|
81
|
+
h[part] = target.to_param
|
82
|
+
elsif part == :format
|
83
|
+
# Nothing
|
84
|
+
elsif target.respond_to?(part)
|
85
|
+
h[part] = target.public_send(part)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
else
|
89
|
+
target
|
90
|
+
end
|
59
91
|
end
|
60
92
|
|
61
|
-
|
93
|
+
# Generate the path
|
94
|
+
path = routes[action].format(formattable || EMPTY_HASH)
|
62
95
|
|
63
96
|
if path.present? && opts.present?
|
64
97
|
uri = URI.parse(path)
|
@@ -70,74 +103,85 @@ module Effective
|
|
70
103
|
end
|
71
104
|
|
72
105
|
def actions
|
73
|
-
routes.keys
|
106
|
+
@route_actions ||= routes.keys
|
74
107
|
end
|
75
108
|
|
76
109
|
def crud_actions
|
77
|
-
|
110
|
+
@crud_actions ||= (actions & CRUD_ACTIONS)
|
78
111
|
end
|
79
112
|
|
80
113
|
# GET actions
|
81
114
|
def collection_actions
|
82
|
-
|
115
|
+
@collection_actions ||= (
|
116
|
+
routes.map { |_, route| route.defaults[:action].to_sym if is_collection_route?(route) }.tap(&:compact!)
|
117
|
+
)
|
83
118
|
end
|
84
119
|
|
85
120
|
def collection_get_actions
|
86
|
-
|
121
|
+
@collection_get_actions ||= (
|
122
|
+
routes.map { |_, route| route.defaults[:action].to_sym if is_collection_route?(route) && is_get_route?(route) }.tap(&:compact!)
|
123
|
+
)
|
87
124
|
end
|
88
125
|
|
89
126
|
def collection_post_actions
|
90
|
-
|
127
|
+
@collection_post_actions ||= (
|
128
|
+
routes.map { |_, route| route.defaults[:action].to_sym if is_collection_route?(route) && is_post_route?(route) }.tap(&:compact!)
|
129
|
+
)
|
91
130
|
end
|
92
131
|
|
93
132
|
# All actions
|
94
133
|
def member_actions
|
95
|
-
|
134
|
+
@member_actions ||= (
|
135
|
+
routes.map { |_, route| route.defaults[:action].to_sym if is_member_route?(route) }.tap(&:compact!)
|
136
|
+
)
|
96
137
|
end
|
97
138
|
|
98
139
|
# GET actions
|
99
140
|
def member_get_actions
|
100
|
-
|
141
|
+
@member_get_actions ||= (
|
142
|
+
routes.map { |_, route| route.defaults[:action].to_sym if is_member_route?(route) && is_get_route?(route) }.tap(&:compact!)
|
143
|
+
)
|
101
144
|
end
|
102
145
|
|
103
146
|
def member_delete_actions
|
104
|
-
|
147
|
+
@member_delete_actions ||= (
|
148
|
+
routes.map { |_, route| route.defaults[:action].to_sym if is_member_route?(route) && is_delete_route?(route) }.tap(&:compact!)
|
149
|
+
)
|
105
150
|
end
|
106
151
|
|
107
152
|
# POST/PUT/PATCH actions
|
108
153
|
def member_post_actions
|
109
|
-
|
154
|
+
@member_post_actions ||= (
|
155
|
+
routes.map { |_, route| route.defaults[:action].to_sym if is_member_route?(route) && is_post_route?(route) }.tap(&:compact!)
|
156
|
+
)
|
110
157
|
end
|
111
158
|
|
112
159
|
# Same as controller_path in the view
|
113
160
|
def controller_path
|
114
|
-
[namespace, plural_name].compact * '/'
|
161
|
+
[namespace, plural_name].compact * '/'
|
115
162
|
end
|
116
163
|
|
117
164
|
private
|
118
165
|
|
119
166
|
def is_member_route?(route)
|
120
|
-
(route.path.required_names || []).include?('id'
|
167
|
+
(route.path.required_names || []).include?('id')
|
121
168
|
end
|
122
169
|
|
123
170
|
def is_collection_route?(route)
|
124
|
-
(route.path.required_names || []).include?('id'
|
171
|
+
(route.path.required_names || []).include?('id') == false
|
125
172
|
end
|
126
173
|
|
127
174
|
def is_get_route?(route)
|
128
|
-
route.verb
|
175
|
+
route.verb == 'GET'
|
129
176
|
end
|
130
177
|
|
131
178
|
def is_delete_route?(route)
|
132
|
-
route.verb
|
179
|
+
route.verb == 'DELETE'
|
133
180
|
end
|
134
181
|
|
135
182
|
def is_post_route?(route)
|
136
|
-
|
183
|
+
POST_VERBS.include?(route.verb)
|
137
184
|
end
|
138
185
|
end
|
139
186
|
end
|
140
187
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_sting_literals: true
|
2
|
+
|
1
3
|
module Effective
|
2
4
|
module Resources
|
3
5
|
module Controller
|
@@ -29,22 +31,26 @@ module Effective
|
|
29
31
|
end
|
30
32
|
|
31
33
|
(member_post_actions - crud_actions).each do |action| # default true means it will be overwritten by dsl methods
|
32
|
-
|
34
|
+
action_name = action.to_s.titleize
|
35
|
+
|
36
|
+
buttons[action_name] = case action
|
33
37
|
when :archive
|
34
|
-
{ action: action, default: true, if: -> { !resource.archived? }, class: 'btn btn-danger', 'data-method' => :post, 'data-confirm' => "Really #{
|
38
|
+
{ action: action, default: true, if: -> { !resource.archived? }, class: 'btn btn-danger', 'data-method' => :post, 'data-confirm' => "Really #{action_name} @resource?"}
|
35
39
|
when :unarchive
|
36
|
-
{ action: action, default: true, if: -> { resource.archived? }, 'data-method' => :post, 'data-confirm' => "Really #{
|
40
|
+
{ action: action, default: true, if: -> { resource.archived? }, 'data-method' => :post, 'data-confirm' => "Really #{action_name} @resource?" }
|
37
41
|
else
|
38
|
-
{ action: action, default: true, 'data-method' => :post, 'data-confirm' => "Really #{
|
42
|
+
{ action: action, default: true, 'data-method' => :post, 'data-confirm' => "Really #{action_name} @resource?"}
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
46
|
member_delete_actions.each do |action|
|
47
|
+
action_name = action.to_s.titleize
|
48
|
+
|
43
49
|
if action == :destroy
|
44
50
|
next if buttons.values.find { |v| v[:action] == :archive }.present?
|
45
51
|
buttons['Delete'] = { action: action, default: true, 'data-method' => :delete, 'data-confirm' => "Really delete @resource?" }
|
46
52
|
else
|
47
|
-
buttons[
|
53
|
+
buttons[action_name] = { action: action, default: true, 'data-method' => :delete, 'data-confirm' => "Really #{action_name} @resource?" }
|
48
54
|
end
|
49
55
|
end
|
50
56
|
|
@@ -66,33 +72,39 @@ module Effective
|
|
66
72
|
# It is used by datatables
|
67
73
|
def resource_actions
|
68
74
|
{}.tap do |actions|
|
69
|
-
|
75
|
+
member_get_actions.reverse_each do |action|
|
76
|
+
next unless crud_actions.include?(action)
|
70
77
|
actions[action.to_s.titleize] = { action: action, default: true }
|
71
78
|
end
|
72
79
|
|
73
|
-
|
80
|
+
member_get_actions.each do |action|
|
81
|
+
next if crud_actions.include?(action)
|
74
82
|
actions[action.to_s.titleize] = { action: action, default: true }
|
75
83
|
end
|
76
84
|
|
77
|
-
|
78
|
-
|
85
|
+
member_post_actions.each do |action|
|
86
|
+
next if crud_actions.include?(action)
|
79
87
|
|
80
|
-
|
88
|
+
action_name = action.to_s.titleize
|
89
|
+
|
90
|
+
actions[action_name] = case action
|
81
91
|
when :archive
|
82
|
-
{ action: action, default: true, if: -> { !resource.archived? }, class: 'btn btn-danger', 'data-method' => :post, 'data-confirm' => "Really #{
|
92
|
+
{ action: action, default: true, if: -> { !resource.archived? }, class: 'btn btn-danger', 'data-method' => :post, 'data-confirm' => "Really #{action_name} @resource?"}
|
83
93
|
when :unarchive
|
84
|
-
{ action: action, default: true, if: -> { resource.archived? }, 'data-method' => :post, 'data-confirm' => "Really #{
|
94
|
+
{ action: action, default: true, if: -> { resource.archived? }, 'data-method' => :post, 'data-confirm' => "Really #{action_name} @resource?" }
|
85
95
|
else
|
86
|
-
{ action: action, default: true, 'data-method' => :post, 'data-confirm' => "Really #{
|
96
|
+
{ action: action, default: true, 'data-method' => :post, 'data-confirm' => "Really #{action_name} @resource?" }
|
87
97
|
end
|
88
98
|
end
|
89
99
|
|
90
100
|
member_delete_actions.each do |action|
|
101
|
+
action_name = action.to_s.titleize
|
102
|
+
|
91
103
|
if action == :destroy
|
92
|
-
next if actions.
|
104
|
+
next if actions.find { |_, v| v[:action] == :archive }.present?
|
93
105
|
actions['Delete'] = { action: action, default: true, 'data-method' => :delete, 'data-confirm' => "Really delete @resource?" }
|
94
106
|
else
|
95
|
-
actions[
|
107
|
+
actions[action_name] = { action: action, default: true, 'data-method' => :delete, 'data-confirm' => "Really #{action_name} @resource?" }
|
96
108
|
end
|
97
109
|
end
|
98
110
|
end
|
@@ -6,8 +6,40 @@ module Effective
|
|
6
6
|
|
7
7
|
def _initialize_input(input, namespace: nil)
|
8
8
|
@initialized_name = input
|
9
|
+
@model_klass = _klass_by_input(input)
|
9
10
|
|
10
|
-
|
11
|
+
# Consider namespaces
|
12
|
+
if namespace
|
13
|
+
@namespaces = (namespace.kind_of?(String) ? namespace.split('/') : Array(namespace))
|
14
|
+
end
|
15
|
+
|
16
|
+
if input.kind_of?(Array) && @namespaces.blank?
|
17
|
+
@namespaces = input[0...-1].map { |input| input.to_s.presence }.compact
|
18
|
+
end
|
19
|
+
|
20
|
+
# Consider relation
|
21
|
+
if input.kind_of?(ActiveRecord::Relation)
|
22
|
+
@relation ||= input
|
23
|
+
end
|
24
|
+
|
25
|
+
if input.kind_of?(ActiveRecord::Reflection::MacroReflection) && input.scope
|
26
|
+
@relation ||= klass.where(nil).merge(input.scope)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Consider instance
|
30
|
+
if klass && input.instance_of?(klass)
|
31
|
+
@instance ||= input
|
32
|
+
end
|
33
|
+
|
34
|
+
if klass && input.kind_of?(Array) && input.last.instance_of?(klass)
|
35
|
+
@instance ||= input.last
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def _klass_by_input(input)
|
40
|
+
case input
|
41
|
+
when Array
|
42
|
+
_klass_by_input(input.last)
|
11
43
|
when String, Symbol
|
12
44
|
_klass_by_name(input)
|
13
45
|
when Class
|
@@ -24,22 +56,6 @@ module Effective
|
|
24
56
|
when nil ; raise 'expected a string or class'
|
25
57
|
else ; _klass_by_name(input.class.name)
|
26
58
|
end
|
27
|
-
|
28
|
-
if namespace
|
29
|
-
@namespaces = (namespace.kind_of?(String) ? namespace.split('/') : Array(namespace))
|
30
|
-
end
|
31
|
-
|
32
|
-
if input.kind_of?(ActiveRecord::Relation)
|
33
|
-
@relation = input
|
34
|
-
end
|
35
|
-
|
36
|
-
if input.kind_of?(ActiveRecord::Reflection::MacroReflection) && input.scope
|
37
|
-
@relation = klass.where(nil).merge(input.scope)
|
38
|
-
end
|
39
|
-
|
40
|
-
if klass && input.instance_of?(klass)
|
41
|
-
@instance = input
|
42
|
-
end
|
43
59
|
end
|
44
60
|
|
45
61
|
def _klass_by_name(input)
|
@@ -48,6 +64,7 @@ module Effective
|
|
48
64
|
|
49
65
|
names = input.split('/')
|
50
66
|
|
67
|
+
# Crazy classify
|
51
68
|
0.upto(names.length-1) do |index|
|
52
69
|
class_name = names[index..-1].map { |name| name.classify } * '::'
|
53
70
|
klass = class_name.safe_constantize
|
@@ -64,35 +81,19 @@ module Effective
|
|
64
81
|
end
|
65
82
|
end
|
66
83
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
def _initialize_written
|
72
|
-
@written_attributes = []
|
73
|
-
@written_belong_tos = []
|
74
|
-
@written_scopes = []
|
75
|
-
|
76
|
-
return unless File.exists?(model_file)
|
77
|
-
|
78
|
-
Effective::CodeReader.new(model_file) do |reader|
|
79
|
-
first = reader.index { |line| line == '# Attributes' }
|
80
|
-
last = reader.index(from: first) { |line| line.start_with?('#') == false && line.length > 0 } if first
|
81
|
-
|
82
|
-
if first && last
|
83
|
-
@written_attributes = reader.select(from: first+1, to: last-1).map do |line|
|
84
|
-
Effective::Attribute.parse_written(line).presence
|
85
|
-
end.compact
|
86
|
-
end
|
87
|
-
|
88
|
-
@written_belong_tos = reader.select { |line| line.start_with?('belongs_to ') }.map do |line|
|
89
|
-
line.scan(/belongs_to\s+:(\w+)/).flatten.first
|
90
|
-
end
|
84
|
+
# Crazy engine
|
85
|
+
if names[0] == 'admin'
|
86
|
+
class_name = (['effective'] + names[1..-1]).map { |name| name.classify } * '::'
|
87
|
+
klass = class_name.safe_constantize
|
91
88
|
|
92
|
-
|
93
|
-
|
89
|
+
if klass.present?
|
90
|
+
@namespaces ||= names[0...-1]
|
91
|
+
@model_klass = klass
|
92
|
+
return klass
|
94
93
|
end
|
95
94
|
end
|
95
|
+
|
96
|
+
nil
|
96
97
|
end
|
97
98
|
|
98
99
|
end
|
@@ -11,6 +11,9 @@ module Effective
|
|
11
11
|
"#{namespaced_class_name.pluralize}Datatable".safe_constantize ||
|
12
12
|
"#{class_name.pluralize.camelize}Datatable".safe_constantize ||
|
13
13
|
"#{name.pluralize.camelize}Datatable".safe_constantize ||
|
14
|
+
"#{namespaced_class_name.pluralize.gsub('::', '')}Datatable".safe_constantize ||
|
15
|
+
"#{class_name.pluralize.camelize.gsub('::', '')}Datatable".safe_constantize ||
|
16
|
+
"#{name.pluralize.camelize.gsub('::', '')}Datatable".safe_constantize ||
|
14
17
|
"Effective::Datatables::#{namespaced_class_name.pluralize}".safe_constantize ||
|
15
18
|
"Effective::Datatables::#{class_name.pluralize.camelize}".safe_constantize ||
|
16
19
|
"Effective::Datatables::#{name.pluralize.camelize}".safe_constantize
|
@@ -11,6 +11,10 @@ module Effective
|
|
11
11
|
name.pluralize
|
12
12
|
end
|
13
13
|
|
14
|
+
def resource_name # 'effective_post' used by permitted params
|
15
|
+
@resource_name ||= ((klass.present? ? klass.name : initialized_name).to_s.split(SPLIT).join('_') || '').singularize.underscore
|
16
|
+
end
|
17
|
+
|
14
18
|
def initialized_name
|
15
19
|
@initialized_name
|
16
20
|
end
|
@@ -158,6 +158,12 @@ module Effective
|
|
158
158
|
else
|
159
159
|
relation.where("#{sql_column} = ?", term)
|
160
160
|
end
|
161
|
+
when :uuid
|
162
|
+
if fuzzy
|
163
|
+
relation.where("#{sql_column}::text #{ilike} ?", "%#{term}%")
|
164
|
+
else
|
165
|
+
relation.where("#{sql_column}::text = ?", term)
|
166
|
+
end
|
161
167
|
else
|
162
168
|
raise "unsupported sql type #{sql_type}"
|
163
169
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
- permitted_resource_actions(resource, actions).each do |label, opts|
|
2
|
-
|
2
|
+
- action = opts.delete(:action)
|
3
|
+
= link_to(label, (effective_resource.action_path(action, resource) || '#'), opts)
|
3
4
|
|
4
5
|
= instance_exec(resource, &format_block) if local_assigns[:format_block]
|
5
6
|
= yield if block_given?
|
@@ -1,6 +1,9 @@
|
|
1
1
|
= dropdown(variation: :dropleft, btn_class: btn_class) do
|
2
2
|
- permitted_resource_actions(resource, actions).each do |label, opts|
|
3
|
-
|
3
|
+
- action = opts.delete(:action)
|
4
|
+
- opts.delete(:class)
|
5
|
+
|
6
|
+
= dropdown_link_to(label, (effective_resource.action_path(action, resource) || '#'), opts)
|
4
7
|
|
5
8
|
= instance_exec(resource, &format_block) if local_assigns[:format_block]
|
6
9
|
= yield(resource) if block_given?
|
@@ -1,5 +1,8 @@
|
|
1
1
|
- permitted_resource_actions(resource, actions).each do |label, opts|
|
2
|
-
|
2
|
+
- action = opts.delete(:action)
|
3
|
+
- opts.delete(:class)
|
4
|
+
|
5
|
+
= glyphicon_to(action, (effective_resource.action_path(action, resource) || '#'), opts)
|
3
6
|
|
4
7
|
= instance_exec(resource, &format_block) if local_assigns[:format_block]
|
5
8
|
= yield(resource) if block_given?
|
data/lib/effective_resources.rb
CHANGED
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: 1.
|
4
|
+
version: 1.6.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: 2020-
|
11
|
+
date: 2020-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,6 +24,76 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 4.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sqlite3
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: effective_datatables
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: effective_developer
|
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: haml
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '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'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry-byebug
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
27
97
|
description: Make any controller an effective resource controller.
|
28
98
|
email:
|
29
99
|
- info@codeandeffect.com
|
@@ -113,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
183
|
- !ruby/object:Gem::Version
|
114
184
|
version: '0'
|
115
185
|
requirements: []
|
116
|
-
rubygems_version: 3.1.
|
186
|
+
rubygems_version: 3.1.2
|
117
187
|
signing_key:
|
118
188
|
specification_version: 4
|
119
189
|
summary: Make any controller an effective resource controller.
|