effective_resources 0.9.5 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/effective/crud_controller.rb +23 -546
  3. data/app/controllers/concerns/effective/crud_controller/actions.rb +289 -0
  4. data/app/controllers/concerns/effective/crud_controller/dsl.rb +81 -0
  5. data/app/controllers/concerns/effective/crud_controller/paths.rb +87 -0
  6. data/app/controllers/concerns/effective/crud_controller/permitted_params.rb +66 -0
  7. data/app/controllers/concerns/effective/crud_controller/save.rb +77 -0
  8. data/app/controllers/concerns/effective/crud_controller/submits.rb +122 -0
  9. data/app/helpers/effective_resources_helper.rb +51 -52
  10. data/app/helpers/effective_resources_private_helper.rb +69 -0
  11. data/app/models/concerns/effective_resource.rb +24 -0
  12. data/app/models/effective/model_reader.rb +29 -0
  13. data/app/models/effective/resource.rb +6 -2
  14. data/app/models/effective/resources/actions.rb +10 -10
  15. data/app/models/effective/resources/associations.rb +5 -0
  16. data/app/models/effective/resources/attributes.rb +40 -27
  17. data/app/models/effective/resources/controller.rb +81 -0
  18. data/app/models/effective/resources/forms.rb +0 -51
  19. data/app/models/effective/resources/init.rb +19 -17
  20. data/app/models/effective/resources/klass.rb +6 -8
  21. data/app/models/effective/resources/model.rb +23 -0
  22. data/app/models/effective/resources/naming.rb +7 -3
  23. data/app/models/effective/resources/paths.rb +4 -63
  24. data/app/models/effective/resources/relation.rb +4 -1
  25. data/app/models/effective/resources/sql.rb +1 -1
  26. data/app/views/application/create.js.erb +1 -1
  27. data/app/views/application/edit.html.haml +2 -2
  28. data/app/views/application/index.html.haml +1 -1
  29. data/app/views/application/member_action.js.erb +1 -1
  30. data/app/views/application/new.html.haml +3 -1
  31. data/app/views/application/show.html.haml +1 -1
  32. data/app/views/application/update.js.erb +1 -1
  33. data/app/views/effective/resource/_actions.html.haml +3 -32
  34. data/app/views/effective/resource/_actions_dropleft.html.haml +4 -26
  35. data/app/views/effective/resource/_actions_glyphicons.html.haml +4 -10
  36. data/lib/effective_resources/engine.rb +1 -0
  37. data/lib/effective_resources/version.rb +1 -1
  38. metadata +14 -3
@@ -0,0 +1,66 @@
1
+ module Effective
2
+ module CrudController
3
+ module PermittedParams
4
+ BLACKLIST = [:created_at, :updated_at]
5
+
6
+ # This is only available to models that use the effective_resource do ... end attributes block
7
+ # It will be called last, and only for those resources
8
+ # params.require(effective_resource.name).permit!
9
+ def resource_permitted_params
10
+ raise 'expected resource class to have effective_resource do .. end' if effective_resource.model.blank?
11
+
12
+ permitted_params = permitted_params_for(resource)
13
+
14
+ if Rails.env.development?
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]})"
17
+ end
18
+
19
+ params.require(effective_resource.name).permit(*permitted_params)
20
+ end
21
+
22
+ private
23
+
24
+ def permitted_params_for(resource)
25
+ effective_resource = if resource.kind_of?(Class)
26
+ resource.effective_resource if resource.respond_to?(:effective_resource)
27
+ else
28
+ resource.class.effective_resource if resource.class.respond_to?(:effective_resource)
29
+ end
30
+
31
+ # That class doesn't implement effective_resource do .. end block
32
+ return [] unless effective_resource.present?
33
+
34
+ # This is :id, all belongs_to ids, and model attributes
35
+ permitted_params = effective_resource.permitted_attributes.select do |name, (_, atts)|
36
+ if BLACKLIST.include?(name)
37
+ false
38
+ elsif atts.blank? || !atts.key?(:permitted)
39
+ true # Default is true
40
+ else
41
+ permitted = (atts[:permitted].respond_to?(:call) ? instance_exec(&atts[:permitted]) : atts[:permitted])
42
+
43
+ if permitted == true || permitted == false
44
+ permitted
45
+ elsif permitted == nil || permitted == :blank
46
+ effective_resource.namespaces.length == 0
47
+ else # A symbol, string, or array of, representing the namespace
48
+ (effective_resource.namespaces & Array(permitted).map(&:to_s)).present?
49
+ end
50
+ end
51
+ end.keys
52
+
53
+ # Recursively add any accepts_nested_resources
54
+ effective_resource.nested_resources.each do |nested|
55
+ if (nested_params = permitted_params_for(nested.klass)).present?
56
+ nested_params.insert(nested_params.rindex { |obj| !obj.kind_of?(Hash)} + 1, :_destroy)
57
+ permitted_params << { "#{nested.plural_name}_attributes".to_sym => nested_params }
58
+ end
59
+ end
60
+
61
+ permitted_params
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,77 @@
1
+ module Effective
2
+ module CrudController
3
+ module Save
4
+
5
+ # Based on the incoming params[:commit] or passed action. Merges all options.
6
+ def commit_action(action = nil)
7
+ config = (['create', 'update'].include?(params[:action]) ? self.class.submits : self.class.buttons)
8
+
9
+ commit = if action.present?
10
+ config[action.to_s] || config.find { |_, v| v[:action] == action }.try(:last) || { action: action }
11
+ else
12
+ config[params[:commit].to_s] || config.find { |_, v| v[:action] == :save }.try(:last) || { action: :save }
13
+ end
14
+
15
+ commit.reverse_merge!(self.class.ons[commit[:action]]) if self.class.ons[commit[:action]]
16
+
17
+ commit
18
+ end
19
+
20
+ # This calls the appropriate member action, probably save!, on the resource.
21
+ def save_resource(resource, action = :save, &block)
22
+ raise "expected @#{resource_name} to respond to #{action}!" unless resource.respond_to?("#{action}!")
23
+
24
+ resource.current_user ||= current_user if resource.respond_to?(:current_user=)
25
+
26
+ ActiveRecord::Base.transaction do
27
+ begin
28
+ if resource.public_send("#{action}!") == false
29
+ raise("failed to #{action} #{resource}")
30
+ end
31
+
32
+ yield if block_given?
33
+
34
+ run_callbacks(:resource_save)
35
+ return true
36
+ rescue => e
37
+ Rails.logger.info "Failed to #{action}: #{e.message}" if Rails.env.development?
38
+
39
+ if resource.respond_to?(:restore_attributes) && resource.persisted?
40
+ resource.restore_attributes(['status', 'state'])
41
+ end
42
+
43
+ flash.delete(:success)
44
+ flash.now[:danger] = flash_danger(resource, action, e: e)
45
+ raise ActiveRecord::Rollback
46
+ end
47
+ end
48
+
49
+ run_callbacks(:resource_error)
50
+ false
51
+ end
52
+
53
+ def resource_flash(status, resource, action)
54
+ submit = commit_action(action)
55
+ message = submit[status].respond_to?(:call) ? instance_exec(&submit[status]) : submit[status]
56
+ return message if message.present?
57
+
58
+ case status
59
+ when :success then flash_success(resource, action)
60
+ when :danger then flash_danger(resource, action)
61
+ else
62
+ raise "unknown resource flash status: #{status}"
63
+ end
64
+ end
65
+
66
+ def reload_resource
67
+ self.resource.reload if resource.respond_to?(:reload)
68
+ end
69
+
70
+ # Should return a new resource based on the passed one
71
+ def duplicate_resource(resource)
72
+ resource.dup
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,122 @@
1
+ module Effective
2
+ module CrudController
3
+ module Submits
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ # { 'Save' => { action: save, ...}}
8
+ def submits
9
+ @_effective_submits ||= effective_resource.submits
10
+ end
11
+
12
+ # { 'Approve' => { action: approve, ...}}
13
+ def buttons
14
+ @_effective_buttons ||= effective_resource.buttons
15
+ end
16
+
17
+ # { :approve => { redirect: .. }}
18
+ def ons
19
+ @_effective_ons ||= effective_resource.ons
20
+ end
21
+
22
+ # :only, :except, :if, :unless, :redirect, :success, :danger, :class
23
+ def _insert_submit(action, label = nil, args = {})
24
+ raise 'expected args to be a Hash or false' unless args.kind_of?(Hash) || args == false
25
+
26
+ if label == false
27
+ submits.delete_if { |label, args| args[:action] == action }; return
28
+ end
29
+
30
+ if args == false
31
+ submits.delete(label); return
32
+ end
33
+
34
+ if label # Overwrite the default member action when given a custom submit
35
+ submits.delete_if { |label, args| args[:default] && args[:action] == action }
36
+ end
37
+
38
+ if args.key?(:if) && args[:if].respond_to?(:call) == false
39
+ raise "expected if: to be callable. Try submit :approve, 'Save and Approve', if: -> { finished? }"
40
+ end
41
+
42
+ if args.key?(:unless) && args[:unless].respond_to?(:call) == false
43
+ raise "expected unless: to be callable. Try submit :approve, 'Save and Approve', unless: -> { declined? }"
44
+ end
45
+
46
+ if args.key?(:only)
47
+ args[:only] = Array(args[:only])
48
+ raise "expected only: to be a symbol or array of symbols. Try submit :approve, 'Save and Approve', only: [:edit]" unless args[:only].all? { |v| v.kind_of?(Symbol) }
49
+ end
50
+
51
+ if args.key?(:except)
52
+ args[:except] = Array(args[:except])
53
+ raise "expected except: to be a symbol or array of symbols. Try submit :approve, 'Save and Approve', except: [:edit]" unless args[:except].all? { |v| v.kind_of?(Symbol) }
54
+ end
55
+
56
+ if args.key?(:redirect_to) # Normalize this option to redirect
57
+ args[:redirect] = args.delete(:redirect_to)
58
+ end
59
+
60
+ args[:action] = action
61
+
62
+ (submits[label] ||= {}).merge!(args)
63
+ end
64
+
65
+ def _insert_button(action, label = nil, args = {})
66
+ raise 'expected args to be a Hash or false' unless args.kind_of?(Hash) || args == false
67
+
68
+ if label == false
69
+ buttons.delete_if { |label, args| args[:action] == action }; return
70
+ end
71
+
72
+ if args == false
73
+ buttons.delete(label); return
74
+ end
75
+
76
+ if label # Overwrite the default member action when given a custom label
77
+ buttons.delete_if { |label, args| args[:default] && args[:action] == action }
78
+ end
79
+
80
+ if args.key?(:if) && args[:if].respond_to?(:call) == false
81
+ raise "expected if: to be callable. Try button :approve, 'Approve', if: -> { finished? }"
82
+ end
83
+
84
+ if args.key?(:unless) && args[:unless].respond_to?(:call) == false
85
+ raise "expected unless: to be callable. Try button :approve, 'Approve', unless: -> { declined? }"
86
+ end
87
+
88
+ if args.key?(:only)
89
+ args[:only] = Array(args[:only])
90
+ raise "expected only: to be a symbol or array of symbols. Try button :approve, 'Save and Approve', only: [:edit]" unless args[:only].all? { |v| v.kind_of?(Symbol) }
91
+ end
92
+
93
+ if args.key?(:except)
94
+ args[:except] = Array(args[:except])
95
+ raise "expected except: to be a symbol or array of symbols. Try button :approve, 'Save and Approve', except: [:edit]" unless args[:except].all? { |v| v.kind_of?(Symbol) }
96
+ end
97
+
98
+ if args.key?(:redirect_to) # Normalize this option to redirect
99
+ args[:redirect] = args.delete(:redirect_to)
100
+ end
101
+
102
+ args[:action] = action
103
+
104
+ (buttons[label] ||= {}).merge!(args)
105
+ end
106
+
107
+ def _insert_on(action, args = {})
108
+ raise 'expected args to be a Hash' unless args.kind_of?(Hash)
109
+
110
+ if args.key?(:redirect_to) # Normalize this option to redirect
111
+ args[:redirect] = args.delete(:redirect_to)
112
+ end
113
+
114
+ args[:action] = action
115
+
116
+ (ons[action] ||= {}).merge!(args)
117
+ end
118
+ end
119
+
120
+ end
121
+ end
122
+ end
@@ -1,41 +1,49 @@
1
1
  module EffectiveResourcesHelper
2
2
 
3
- def effective_submit(form, options = {}, &block) # effective_bootstrap
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)
6
- buttons = actions.map { |name, opts| form.save(name, opts) }.join.html_safe
3
+ # effective_bootstrap
4
+ def effective_submit(form, options = {}, &block)
5
+ actions = (controller.respond_to?(:effective_resource) ? controller.class : find_effective_resource).submits
6
+ actions = permitted_resource_actions(form.object, actions)
7
+
8
+ submits = actions.map { |name, opts| form.save(name, opts.except(:action, :title, 'data-method', 'data-confirm')) }.join.html_safe
7
9
 
8
10
  form.submit('', options) do
9
- (block_given? ? capture(&block) : ''.html_safe) + buttons
11
+ (block_given? ? capture(&block) : ''.html_safe) + submits
10
12
  end
11
13
  end
12
14
 
13
15
  # effective_form_inputs
14
16
  def simple_form_submit(form, options = {}, &block)
15
- resource = (controller.class.respond_to?(:effective_resource) ? controller.class.effective_resource : Effective::Resource.new(controller_path))
16
- actions = resource.submits_for(form.object, controller: controller)
17
+ actions = (controller.respond_to?(:effective_resource) ? controller.class : find_effective_resource).submits
18
+ actions = permitted_resource_actions(form.object, actions)
17
19
 
18
- buttons = actions.map { |action| form.button(:submit, *action) }
20
+ submits = actions.map { |name, opts| form.button(:submit, name, opts.except(:action, :title, 'data-method', 'data-confirm')) }.join('&nbsp;').html_safe
19
21
 
20
22
  # I think this is a bug. I can't override default button class when passing my own class: variable. it merges them.
21
- if defined?(SimpleForm) && (btn_class = SimpleForm.button_class).present?
22
- buttons = buttons.map { |button| button.sub(btn_class, '') }
23
+ if (btn_class = SimpleForm.button_class).present?
24
+ submits = submits.map { |submit| submit.sub(btn_class, '') }
23
25
  end
24
26
 
25
27
  wrapper_options = { class: 'form-actions' }.merge(options.delete(:wrapper_html) || {})
26
28
 
27
29
  content_tag(:div, wrapper_options) do
28
- (block_given? ? capture(&block) : ''.html_safe) + buttons.join('&nbsp;').html_safe
30
+ (block_given? ? capture(&block) : ''.html_safe) + submits
29
31
  end
30
32
  end
31
33
 
32
- def simple_form_save(form, label = 'Save', options = {}, &block)
33
- wrapper_options = { class: 'form-actions' }.merge(options.delete(:wrapper_html) || {})
34
- options = { class: 'btn btn-primary', data: { disable_with: 'Saving...'} }.merge(options)
34
+ def render_resource_buttons(resource, atts = {}, &block)
35
+ effective_resource = find_effective_resource
36
+ actions = (controller.respond_to?(:effective_resource) ? controller.class : effective_resource).buttons
35
37
 
36
- content_tag(:div, wrapper_options) do
37
- form.button(:submit, label, options) + (capture(&block) if block_given?)
38
+ actions = if resource.kind_of?(Class)
39
+ actions.select { |_, v| effective_resource.collection_get_actions.include?(v[:action]) }
40
+ elsif resource.respond_to?(:persisted?) && resource.persisted?
41
+ actions.select { |_, v| effective_resource.member_actions.include?(v[:action]) }
42
+ else
43
+ {}
38
44
  end
45
+
46
+ render_resource_actions(resource, atts.merge(actions: actions), &block)
39
47
  end
40
48
 
41
49
  # Renders the effective/resource view partial for this resource
@@ -46,29 +54,34 @@ module EffectiveResourcesHelper
46
54
  # partial: :dropleft|:glyphicons|string
47
55
  # locals: {} render locals
48
56
  # you can also pass all action names and true/false such as edit: true, show: false
49
- def render_resource_actions(resource, instance = nil, atts = {}, &block)
50
- (atts = instance; instance = nil) if instance.kind_of?(Hash) && atts.blank?
51
- raise 'expected first argument to be an Effective::Resource' unless resource.kind_of?(Effective::Resource)
57
+ def render_resource_actions(resource, atts = {}, &block)
58
+ raise 'expected first argument to be an ActiveRecord::Base object or Array of objects' unless resource.kind_of?(ActiveRecord::Base) || resource.kind_of?(Class) || resource.kind_of?(Array)
52
59
  raise 'expected attributes to be a Hash' unless atts.kind_of?(Hash)
53
60
 
54
61
  locals = atts.delete(:locals) || {}
55
- namespace = atts.delete(:namespace) || (resource.namespace.to_sym if resource.namespace)
56
62
  partial = atts.delete(:partial)
57
63
  spacer_template = locals.delete(:spacer_template)
58
64
 
59
- partial = ['effective/resource/actions', partial.to_s].join('_') if partial.kind_of?(Symbol)
60
- partial = (partial.presence || 'effective/resource/actions') + '.html'
65
+ effective_resource = (atts.delete(:effective_resource) || find_effective_resource)
66
+ actions = atts.delete(:actions) || effective_resource.resource_actions
67
+ namespace = atts.delete(:namespace) || (effective_resource.namespace.to_sym if effective_resource.namespace)
61
68
 
62
- actions = (instance ? (resource.member_get_actions + resource.member_delete_actions) : resource.collection_get_actions)
63
- actions = (actions & resource.crud_actions) if atts.delete(:crud)
69
+ # Filter Actions
70
+ action_keys = actions.map { |_, v| v[:action] }
71
+ raise "unknown action for #{effective_resource.name}: #{(atts.keys - action_keys).join(' ')}." if (atts.keys - action_keys).present?
72
+ actions = actions.select { |_, v| atts[v[:action]].respond_to?(:call) ? instance_exec(&atts[v[:action]]) : (atts[v[:action]] != false) }
64
73
 
65
- raise "unknown action for #{resource.name}: #{(atts.keys - actions).join(' ')}." if (atts.keys - actions).present?
66
- actions = (actions - atts.reject { |_, v| v }.keys + atts.select { |_, v| v }.keys).uniq
74
+ # Select Partial
75
+ partial = ['effective/resource/actions', partial.to_s].join('_') if partial.kind_of?(Symbol)
76
+ partial = (partial.presence || 'effective/resource/actions') + '.html'
67
77
 
68
- locals = { resource: instance, effective_resource: resource, namespace: namespace, actions: actions }.compact.merge(locals)
78
+ # Assign Locals
79
+ locals = { resource: resource, effective_resource: effective_resource, namespace: namespace, actions: actions }.compact.merge(locals)
69
80
 
70
- if instance.kind_of?(Array)
71
- render(partial: partial, collection: instance, as: :resource, locals: locals.except(:resource), spacer_template: spacer_template)
81
+ # Render
82
+ if resource.kind_of?(Array)
83
+ locals[:format_block] = block if block_given?
84
+ render(partial: partial, collection: resource, as: :resource, locals: locals.except(:resource), spacer_template: spacer_template)
72
85
  elsif block_given?
73
86
  render(partial, locals) { yield }
74
87
  else
@@ -77,43 +90,29 @@ module EffectiveResourcesHelper
77
90
  end
78
91
 
79
92
  # When called from /admin/things/new.html.haml this will render 'admin/things/form', or 'things/form', or 'thing/form'
80
- def render_resource_form(resource, instance = nil, atts = {})
81
- (atts = instance; instance = nil) if instance.kind_of?(Hash) && atts.blank?
82
- raise 'expected first argument to be an Effective::Resource' unless resource.kind_of?(Effective::Resource)
93
+ def render_resource_form(resource, atts = {})
94
+ raise 'expected first argument to be an ActiveRecord::Base object' unless resource.kind_of?(ActiveRecord::Base)
83
95
  raise 'expected attributes to be a Hash' unless atts.kind_of?(Hash)
84
96
 
85
- instance = instance || instance_variable_get('@' + resource.name) || resource.instance
86
- raise "unable to find resource instance. Either pass the instance as the second argument, or assign @#{resource.name}" unless instance
97
+ effective_resource = (atts.delete(:effective_resource) || find_effective_resource)
87
98
 
88
99
  action = atts.delete(:action)
89
- atts = { :namespace => (resource.namespace.to_sym if resource.namespace), resource.name.to_sym => instance }.compact.merge(atts)
100
+ atts = { :namespace => (effective_resource.namespace.to_sym if effective_resource.namespace), effective_resource.name.to_sym => resource }.compact.merge(atts)
90
101
 
91
102
  if lookup_context.template_exists?("form_#{action}", controller._prefixes, :partial)
92
103
  render "form_#{action}", atts
93
104
  elsif lookup_context.template_exists?('form', controller._prefixes, :partial)
94
105
  render 'form', atts
95
- elsif lookup_context.template_exists?('form', resource.plural_name, :partial)
96
- render "#{resource.plural_name}/form", atts
97
- elsif lookup_context.template_exists?('form', resource.name, :partial)
98
- render "#{resource.name}/form", atts
106
+ elsif lookup_context.template_exists?('form', effective_resource.plural_name, :partial)
107
+ render "#{effective_resource.plural_name}/form", atts
108
+ elsif lookup_context.template_exists?('form', effective_resource.name, :partial)
109
+ render "#{effective_resource.name}/form", atts
99
110
  else
100
111
  render 'form', atts # Will raise the regular error
101
112
  end
102
113
  end
103
114
 
104
- def number_to_duration(duration)
105
- duration = duration.to_i
106
- value = duration.abs
107
-
108
- [
109
- ('-' if duration < 0),
110
- ("#{value / 60}h " if value >= 60),
111
- ("#{'%0.2d' % (value % 60)}m" if value > 0),
112
- ('0m' if value == 0),
113
- ].compact.join
114
- end
115
-
116
- ### Tableize attributes
115
+ # Tableize attributes
117
116
  # This is used by effective_orders, effective_logging, effective_trash and effective_mergery
118
117
  def tableize_hash(obj, table: 'table', th: true, sub_table: 'table', sub_th: true, flatten: true)
119
118
  case obj
@@ -0,0 +1,69 @@
1
+ module EffectiveResourcesPrivateHelper
2
+ REPLACE_PAGE_ACTIONS = {'update' => :edit, 'create' => :new}
3
+
4
+ def permitted_resource_actions(resource, actions, effective_resource = nil)
5
+ effective_resource ||= find_effective_resource
6
+
7
+ page_action = REPLACE_PAGE_ACTIONS[params[:action]] || params[:action]&.to_sym || :save
8
+
9
+ actions.select do |commit, args|
10
+ action = (args[:action] == :save ? (resource.new_record? ? :create : :update) : args[:action])
11
+
12
+ (args.key?(:only) ? args[:only].include?(page_action) : true) &&
13
+ (args.key?(:except) ? !args[:except].include?(page_action) : true) &&
14
+ (args.key?(:if) ? controller.instance_exec(&args[:if]) : true) &&
15
+ (args.key?(:unless) ? !controller.instance_exec(&args[:unless]) : true) &&
16
+ EffectiveResources.authorized?(controller, action, resource)
17
+ end.transform_values.with_index do |opts, index|
18
+ action = opts[:action]
19
+
20
+ # Transform data: { ... } hash into 'data-' keys
21
+ data.each { |k, v| opts["data-#{k}"] ||= v } if (data = opts.delete(:data))
22
+
23
+ # Assign data method and confirm
24
+ if effective_resource.member_post_actions.include?(action)
25
+ opts['data-method'] ||= :post
26
+ opts['data-confirm'] ||= "Really #{action} @resource?"
27
+ elsif effective_resource.member_delete_actions.include?(action)
28
+ opts['data-method'] ||= :delete
29
+ opts['data-confirm'] ||= "Really #{action == :destroy ? 'delete' : action.to_s.titleize} @resource?"
30
+ end
31
+
32
+ # Assign class
33
+ opts[:class] ||= (
34
+ if opts['data-method'] == :delete
35
+ 'btn btn-danger'
36
+ elsif index == 0
37
+ 'btn btn-primary'
38
+ elsif defined?(EffectiveBootstrap)
39
+ 'btn btn-secondary'
40
+ else
41
+ 'btn btn-default'
42
+ end
43
+ )
44
+
45
+ # Assign title
46
+ unless action == :save
47
+ opts[:title] ||= case action
48
+ when :edit then "Edit #{resource}"
49
+ when :show then "#{resource}"
50
+ when :destroy then "Delete #{resource}"
51
+ when :index then "All #{effective_resource.human_plural_name.titleize}"
52
+ else "#{action.to_s.titleize} #{resource}"
53
+ end
54
+ end
55
+
56
+ # Replace resource name in any token strings
57
+ if opts['data-confirm']
58
+ opts['data-confirm'].gsub!('@resource', (resource.to_s.presence || effective_resource.human_name))
59
+ end
60
+
61
+ opts.except(:default, :only, :except, :if, :unless, :redirect, :success, :danger)
62
+ end
63
+ end
64
+
65
+ def find_effective_resource
66
+ @_effective_resource ||= (controller.respond_to?(:effective_resource) ? controller.effective_resource : Effective::Resource.new(controller_path))
67
+ end
68
+
69
+ end