effective_resources 1.5.2 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbff7f74429b0acf21d35b75cb64e6fedcdb4b35c2e62080c530d7416dd1d05c
4
- data.tar.gz: 392c8953a3cd59673d093c9fb8c8160951d54866c293e4f7f200d358503e0aab
3
+ metadata.gz: 8623ea704325f309e92ac90f7df48786d1cb44ce3f050628f094ac90a5a74590
4
+ data.tar.gz: 0c08de0bfeb8345152a89a68ab9031446ea455b3d6bcdb9cd39b5eb456be6baf
5
5
  SHA512:
6
- metadata.gz: 24f6a3cc4b8ab73cfd180e79f45ab609fd6cb3af7ef76f24c07b272c82d6ee1087203e76e09f2113e217975f1d29cd550930a99cd82197ccd18985a5f1faa1b0
7
- data.tar.gz: 1b3c4ef600b6aae43357764d6d908141f13453853fb7645ed11bf58f136dcb2265e16fadbaed9cfd627dd1a6d557fe4f14f1a24021e66491e072ad676e174a3e
6
+ metadata.gz: 467e9ca96fca55a286f6104ebb1bb5b32821d796fe31531726114fa723344cbad3cfa3371998759dbd5a75688f6cbffe08345b9053ef756aacf972436340019c
7
+ data.tar.gz: 97bb18a3ea794fe2be6696096b6636f37522a06d1e67a782e1b17794088f60d5132edb736506c50067fc3686502c9768a4e5a640e845cdd62d6c255b08f7505d
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
- prepend_before_action(opts) { @_effective_resource_scope ||= instance_exec(&(block_given? ? block : obj)) }
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.name).permit!
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.name}).permit(#{permitted_params.to_s[1...-1]})"
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.name).permit(*permitted_params)
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.name}).permit!"
27
+ Rails.logger.info "params.require(:#{effective_resource.resource_name}).permit!"
28
28
  end
29
29
 
30
- if params[effective_resource.name].present?
31
- params.require(effective_resource.name).permit!
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.name]).join('_')).permit!
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.name}_attributes".to_sym => nested_params }
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(from_path.presence || resource_redirect_path(action))
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
- actions = if atts.key?(:actions) # We filter out any actions passed to us that aren't supported
78
- available = effective_resource.actions + atts[:actions].map { |k, v| v[:action] if v[:path] }.compact
79
- atts[:actions].inject({}) { |h, (commit, opts)| h[commit] = opts if available.include?(opts[:action]); h }
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]).compact
86
- except = Array(atts[:except]).compact
91
+ only = Array(atts[:only]) if atts[:only].present?
92
+ except = Array(atts[:except]) if atts[:except].present?
87
93
 
88
- actions = actions.select do |_, opts|
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 = ['effective/resource/actions', partial.to_s].join('_') if partial.kind_of?(Symbol)
104
- partial = (partial.presence || 'effective/resource/actions') + '.html'
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.select do |commit, args|
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
- (args.key?(:except) ? !args[:except].include?(page_action) : true) &&
15
- (args.key?(:if) ? executor.instance_exec(&args[:if]) : true) &&
16
- (args.key?(:unless) ? !executor.instance_exec(&args[:unless]) : true) &&
17
- EffectiveResources.authorized?(controller, action, resource)
18
- end.inject({}) do |h, (commit, args)|
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.key?('data-confirm')
36
- opts['data-confirm'] = opts['data-confirm'].gsub('@resource', (resource.to_s.presence || resource.class.name.gsub('::', ' ').underscore.gsub('_', ' ')).to_s)
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'].to_s == 'delete'
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 #{resource}"
56
- when :show then "#{resource}"
57
- when :destroy then "Delete #{resource}"
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} #{resource}"
65
+ else "#{opts[:action].to_s.titleize} #{resource_to_s}"
60
66
  end
61
67
 
62
- h[commit] = opts; h
68
+ h[commit] = opts
63
69
  end
64
70
  end
65
71
 
@@ -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 = [[namespace, plural_name].compact.join('/'.freeze), [namespace, name].compact.join('/'.freeze)]
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
- routes_engine.routes.routes.select do |route|
12
- matches.any? { |match| match == route.defaults[:controller] } && !route.name.to_s.end_with?('root')
13
- end.inject({}) do |h, route|
14
- h[route.defaults[:action].to_sym] = route; h
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.reverse + [Rails.application]).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
- # Effective::Resource.new('effective/order', namespace: :admin)
20
- def routes_engine
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'.freeze) if routes[action].name.present?
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
- # This generates the correct route when an object is overriding to_param
57
- if (resource || instance).respond_to?(:attributes)
58
- formattable = (resource || instance).attributes.symbolize_keys.merge(id: (resource || instance).to_param)
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
- path = routes[action].format(formattable || {}).presence
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
- actions & %i(index new create show edit update destroy)
110
+ @crud_actions ||= (actions & CRUD_ACTIONS)
78
111
  end
79
112
 
80
113
  # GET actions
81
114
  def collection_actions
82
- routes.values.map { |route| route.defaults[:action].to_sym if is_collection_route?(route) }.compact
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
- routes.values.map { |route| route.defaults[:action].to_sym if is_collection_route?(route) && is_get_route?(route) }.compact
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
- routes.values.map { |route| route.defaults[:action].to_sym if is_collection_route?(route) && is_post_route?(route) }.compact
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
- routes.values.map { |route| route.defaults[:action].to_sym if is_member_route?(route) }.compact
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
- routes.values.map { |route| route.defaults[:action].to_sym if is_member_route?(route) && is_get_route?(route) }.compact
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
- routes.values.map { |route| route.defaults[:action].to_sym if is_member_route?(route) && is_delete_route?(route) }.compact
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
- routes.values.map { |route| route.defaults[:action].to_sym if is_member_route?(route) && is_post_route?(route) }.compact
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 * '/'.freeze
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'.freeze)
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'.freeze) == false
171
+ (route.path.required_names || []).include?('id') == false
125
172
  end
126
173
 
127
174
  def is_get_route?(route)
128
- route.verb.to_s.include?('GET'.freeze)
175
+ route.verb == 'GET'
129
176
  end
130
177
 
131
178
  def is_delete_route?(route)
132
- route.verb.to_s.include?('DELETE'.freeze)
179
+ route.verb == 'DELETE'
133
180
  end
134
181
 
135
182
  def is_post_route?(route)
136
- ['POST', 'PUT', 'PATCH'].freeze.any? { |verb| route.verb == verb }
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
- buttons[action.to_s.titleize] = case action
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 #{action} @resource?"}
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 #{action} @resource?" }
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 #{action} @resource?"}
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[action.to_s.titleize] = { action: action, default: true, 'data-method' => :delete, 'data-confirm' => "Really #{action} @resource?" }
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
- (member_get_actions & crud_actions).reverse_each do |action|
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
- (member_get_actions - crud_actions).each do |action|
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
- (member_post_actions - crud_actions).each do |action|
78
- actions[action.to_s.titleize] = { action: action, default: true, 'data-method' => :post, 'data-confirm' => "Really #{action} @resource?" }
85
+ member_post_actions.each do |action|
86
+ next if crud_actions.include?(action)
79
87
 
80
- actions[action.to_s.titleize] = case action
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 #{action} @resource?"}
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 #{action} @resource?" }
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 #{action} @resource?" }
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.values.find { |v| v[:action] == :archive }.present?
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[action.to_s.titleize] = { action: action, default: true, 'data-method' => :delete, 'data-confirm' => "Really #{action} @resource?" }
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
- @model_klass = case input
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
- nil
68
- end
69
-
70
- # Lazy initialized
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
- @written_scopes = reader.select { |line| line.start_with?('scope ') }.map do |line|
93
- line.scan(/scope\s+:(\w+)/).flatten.first
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
@@ -9,8 +9,12 @@ module Effective
9
9
  def datatable_klass
10
10
  if defined?(EffectiveDatatables)
11
11
  "#{namespaced_class_name.pluralize}Datatable".safe_constantize ||
12
+ "#{namespaced_module_name.pluralize}Datatable".safe_constantize ||
13
+ "#{namespaced_class_name.pluralize.gsub('::', '')}Datatable".safe_constantize ||
12
14
  "#{class_name.pluralize.camelize}Datatable".safe_constantize ||
15
+ "#{class_name.pluralize.camelize.gsub('::', '')}Datatable".safe_constantize ||
13
16
  "#{name.pluralize.camelize}Datatable".safe_constantize ||
17
+ "#{name.pluralize.camelize.gsub('::', '')}Datatable".safe_constantize ||
14
18
  "Effective::Datatables::#{namespaced_class_name.pluralize}".safe_constantize ||
15
19
  "Effective::Datatables::#{class_name.pluralize.camelize}".safe_constantize ||
16
20
  "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
@@ -27,6 +31,10 @@ module Effective
27
31
  (Array(namespaces).map { |name| name.to_s.classify } + [class_name]) * '::'
28
32
  end
29
33
 
34
+ def namespaced_module_name # 'Admin::EffectivePosts'
35
+ Array(namespaces).map { |name| name.to_s.classify }.join('::') + '::' + class_name.gsub('::', '')
36
+ end
37
+
30
38
  def namespace # 'admin/things'
31
39
  (namespaces.join('/') if namespaces.present?)
32
40
  end
@@ -1,5 +1,6 @@
1
1
  - permitted_resource_actions(resource, actions).each do |label, opts|
2
- = link_to(label, (effective_resource.action_path(opts[:action], resource) || '#'), opts.except(:action))
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
- = dropdown_link_to(label, (effective_resource.action_path(opts[:action], resource) || '#'), opts.except(:action, :class).merge(btn_class: btn_class))
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
- = glyphicon_to(opts[:action], (effective_resource.action_path(opts[:action], resource) || '#'), opts.except(:action, :class))
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?
@@ -1,4 +1,5 @@
1
1
  require 'effective_resources/engine'
2
+ require 'effective_resources/version'
2
3
 
3
4
  module EffectiveResources
4
5
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveResources
2
- VERSION = '1.5.2'.freeze
2
+ VERSION = '1.6.1'.freeze
3
3
  end
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.5.2
4
+ version: 1.6.1
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-09-18 00:00:00.000000000 Z
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_bootstrap
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_datatables
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.4
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.