effective_resources 1.2.0 → 1.2.1
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/permitted_params.rb +1 -1
- data/app/controllers/concerns/effective/crud_controller/save.rb +12 -4
- data/app/helpers/effective_resources_helper.rb +1 -2
- data/app/models/concerns/acts_as_archived.rb +9 -0
- data/app/models/concerns/acts_as_statused.rb +63 -0
- data/app/models/effective/action_failed.rb +15 -0
- data/app/models/effective/resources/instance.rb +7 -0
- data/app/models/effective/resources/sql.rb +3 -5
- data/app/views/application/member_action.js.erb +4 -1
- data/lib/effective_resources/engine.rb +15 -0
- data/lib/effective_resources/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 435122fff68bc60412b461cd4eadf1b2a1c9543c
|
4
|
+
data.tar.gz: 4a5a64cc84f32cf948dfe3b69e799cfcd74b52bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6675a98f388897cf2b97cd93177f8fc15927b7d85eae40ed1be4b9ac5a45e4ea767c8232994609f469daaec3b84853e0a8dd153693a71a3d78fc9c8ebbdd2b9c
|
7
|
+
data.tar.gz: efc25566f103fd524994ccf0c7f1bd11578ff748311e75ea034e5ca49a15de60cfcbe0fb6080bb77f26615a368855831291076e12261bda73adb8251be788b5d
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Effective
|
2
2
|
module CrudController
|
3
3
|
module PermittedParams
|
4
|
-
BLACKLIST = [:created_at, :updated_at]
|
4
|
+
BLACKLIST = [:created_at, :updated_at, :logged_change_ids]
|
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
|
@@ -30,7 +30,7 @@ module Effective
|
|
30
30
|
run_callbacks(:resource_before_save)
|
31
31
|
|
32
32
|
if resource.public_send("#{save_action}!") == false
|
33
|
-
raise("failed to #{action}
|
33
|
+
raise Effective::ActionFailed.new("failed to #{action}")
|
34
34
|
end
|
35
35
|
|
36
36
|
yield if block_given?
|
@@ -40,8 +40,9 @@ module Effective
|
|
40
40
|
return true
|
41
41
|
rescue => e
|
42
42
|
if Rails.env.development?
|
43
|
-
Rails.logger.info "
|
44
|
-
|
43
|
+
Rails.logger.info " \e[31m\e[1mFAILED\e[0m\e[22m" # bold red
|
44
|
+
Rails.logger.info " Unable to #{action} #{resource} - #{e.class} #{e}"
|
45
|
+
e.backtrace.first(5).each { |line| Rails.logger.info(' ' + line) }
|
45
46
|
end
|
46
47
|
|
47
48
|
if resource.respond_to?(:restore_attributes) && resource.persisted?
|
@@ -49,7 +50,14 @@ module Effective
|
|
49
50
|
end
|
50
51
|
|
51
52
|
flash.now[:danger] = resource_flash(:danger, resource, action, e: e)
|
52
|
-
|
53
|
+
|
54
|
+
case e
|
55
|
+
when Effective::ActionFailed, ActiveRecord::RecordInvalid, RuntimeError
|
56
|
+
raise(ActiveRecord::Rollback) # This is a soft error, we want to display the flash message to user
|
57
|
+
else
|
58
|
+
raise(e) # This is a real error that should be sent to 500. Client should not see the message.
|
59
|
+
end
|
60
|
+
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
@@ -50,8 +50,7 @@ module EffectiveResourcesHelper
|
|
50
50
|
end
|
51
51
|
|
52
52
|
# Renders the effective/resource view partial for this resource
|
53
|
-
# resource is an
|
54
|
-
# instance is an ActiveRecord thing, an Array of ActiveRecord things, or nil
|
53
|
+
# resource is an ActiveRecord thing, an Array of ActiveRecord things, or nil
|
55
54
|
# Atts are everything else. Interesting ones include:
|
56
55
|
|
57
56
|
# partial: :dropleft|:glyphicons|string
|
@@ -42,6 +42,15 @@ module ActsAsArchived
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
module CanCan
|
46
|
+
def acts_as_archived(klass)
|
47
|
+
raise "klass does not implement acts_as_archived" unless klass.acts_as_archived?
|
48
|
+
|
49
|
+
can(:archive, klass) { |obj| !obj.archived? }
|
50
|
+
can(:unarchive, klass) { |obj| obj.archived? }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
45
54
|
module RoutesConcern
|
46
55
|
def acts_as_archived
|
47
56
|
concern :acts_as_archived do
|
@@ -24,6 +24,67 @@ module ActsAsStatused
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
module CanCan
|
28
|
+
# The idea here is you can go forward but you can't go back.
|
29
|
+
def acts_as_statused(klass, only: nil, except: nil)
|
30
|
+
raise "klass does not implement acts_as_statused" unless klass.acts_as_statused?
|
31
|
+
|
32
|
+
statuses = klass.const_get(:STATUSES)
|
33
|
+
instance = klass.new
|
34
|
+
|
35
|
+
only = Array(only).compact
|
36
|
+
except = Array(except).compact
|
37
|
+
|
38
|
+
statuses.each_with_index do |status, index|
|
39
|
+
action = status_active_verb(status, instance)
|
40
|
+
|
41
|
+
next if action.blank?
|
42
|
+
next if only.present? && !only.include?(action)
|
43
|
+
next if except.present? && except.include?(action)
|
44
|
+
|
45
|
+
if index == 0
|
46
|
+
can(action, klass) and next
|
47
|
+
end
|
48
|
+
|
49
|
+
if status == :approved && statuses.include?(:declined)
|
50
|
+
if (position = statuses.index { |status| (status == :approved || status == :declined) }) > 0
|
51
|
+
can(action, klass) { |obj| obj.public_send("#{statuses[position-1]}?") || obj.declined? }
|
52
|
+
next
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
if status == :declined && statuses.include?(:approved)
|
57
|
+
if (position = statuses.index { |status| (status == :approved || status == :declined) }) > 0
|
58
|
+
can(action, klass) { |obj| obj.public_send("#{statuses[position-1]}?") }
|
59
|
+
next
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
can(action, klass) { |obj| obj.public_send("#{statuses[index-1]}?") }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# requested -> request, approved -> approve, declined -> decline, pending -> pending
|
70
|
+
def status_active_verb(status, instance)
|
71
|
+
status = status.to_s.strip
|
72
|
+
|
73
|
+
if status.end_with?('ied')
|
74
|
+
action = status[0...-3] + 'y'
|
75
|
+
return action.to_sym if instance.respond_to?(action + '!')
|
76
|
+
end
|
77
|
+
|
78
|
+
# ed, e, ing
|
79
|
+
[-1, -2, -3].each do |index|
|
80
|
+
action = status[0...index]
|
81
|
+
return action.to_sym if instance.respond_to?(action + '!')
|
82
|
+
end
|
83
|
+
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
27
88
|
included do
|
28
89
|
acts_as_statused_options = @acts_as_statused_options
|
29
90
|
|
@@ -77,6 +138,8 @@ module ActsAsStatused
|
|
77
138
|
|
78
139
|
status_steps.delete("#{sym}_at".to_sym)
|
79
140
|
status_steps.delete("#{sym}_by".to_sym)
|
141
|
+
|
142
|
+
true
|
80
143
|
end
|
81
144
|
|
82
145
|
scope(sym, -> { where(status: sym.to_s) })
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Effective
|
2
|
+
class ActionFailed < StandardError
|
3
|
+
attr_reader :action, :subject
|
4
|
+
|
5
|
+
def initialize(message = nil, action = nil, subject = nil)
|
6
|
+
@message = message
|
7
|
+
@action = action
|
8
|
+
@subject = subject
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
@message || I18n.t(:'unauthorized.default', :default => 'Action Failed')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -4,6 +4,7 @@ module Effective
|
|
4
4
|
attr_accessor :instance
|
5
5
|
|
6
6
|
# This is written for use by effective_logging and effective_trash
|
7
|
+
BLACKLIST = [:logged_changes, :trash]
|
7
8
|
|
8
9
|
def instance
|
9
10
|
@instance || klass.new
|
@@ -18,12 +19,15 @@ module Effective
|
|
18
19
|
# Collect to_s representations of all belongs_to associations
|
19
20
|
if include_associated
|
20
21
|
belong_tos.each do |association|
|
22
|
+
next if BLACKLIST.include?(association.name)
|
21
23
|
attributes[association.name] = instance.send(association.name).to_s
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
27
|
if include_associated || include_nested
|
26
28
|
nested_resources.each do |association|
|
29
|
+
next if BLACKLIST.include?(association.name)
|
30
|
+
|
27
31
|
attributes[association.name] ||= {}
|
28
32
|
|
29
33
|
next if association.options[:through]
|
@@ -39,14 +43,17 @@ module Effective
|
|
39
43
|
|
40
44
|
if include_associated
|
41
45
|
has_ones.each do |association|
|
46
|
+
next if BLACKLIST.include?(association.name)
|
42
47
|
attributes[association.name] = instance.send(association.name).to_s
|
43
48
|
end
|
44
49
|
|
45
50
|
has_manys.each do |association|
|
51
|
+
next if BLACKLIST.include?(association.name)
|
46
52
|
attributes[association.name] = instance.send(association.name).map { |obj| obj.to_s }
|
47
53
|
end
|
48
54
|
|
49
55
|
has_and_belongs_to_manys.each do |association|
|
56
|
+
next if BLACKLIST.include?(association.name)
|
50
57
|
attributes[association.name] = instance.send(association.name).map { |obj| obj.to_s }
|
51
58
|
end
|
52
59
|
end
|
@@ -96,7 +96,9 @@ module Effective
|
|
96
96
|
@_search_columns = names
|
97
97
|
end
|
98
98
|
|
99
|
-
|
99
|
+
def ilike
|
100
|
+
@ilike ||= (postgres? ? 'ILIKE' : 'LIKE') # Only Postgres supports ILIKE, Mysql and Sqlite3 use LIKE
|
101
|
+
end
|
100
102
|
|
101
103
|
def postgres?
|
102
104
|
return @postgres unless @postgres.nil?
|
@@ -108,10 +110,6 @@ module Effective
|
|
108
110
|
@mysql ||= (klass.connection.kind_of?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) rescue false)
|
109
111
|
end
|
110
112
|
|
111
|
-
def ilike
|
112
|
-
@ilike ||= (postgres? ? 'ILIKE' : 'LIKE') # Only Postgres supports ILIKE, Mysql and Sqlite3 use LIKE
|
113
|
-
end
|
114
|
-
|
115
113
|
def is_null(sql_column)
|
116
114
|
mysql? == true ? "ISNULL(#{sql_column})" : "#{sql_column} IS NULL"
|
117
115
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
<% resource = (@_effective_resource || Effective::Resource.new(controller_path)) %>
|
2
2
|
<% @resource = instance_variable_get('@' + resource.name) if resource.name %>
|
3
3
|
|
4
|
-
|
4
|
+
<% unless params[:_datatable_action] %>
|
5
|
+
EffectiveForm.remote_form_payload = "<%= j render_resource_form(@resource, action: action) %>";
|
6
|
+
<% end %>
|
7
|
+
|
5
8
|
EffectiveForm.remote_form_flash = <%= raw flash.to_json %>;
|
6
9
|
|
7
10
|
<% if @resource.respond_to?(:refresh_datatables) && @resource.refresh_datatables.present? %>
|
@@ -33,5 +33,20 @@ module EffectiveResources
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
initializer 'effective_resources.cancancan' do |app|
|
37
|
+
if defined?(CanCan::Ability)
|
38
|
+
CanCan::Ability.module_eval do
|
39
|
+
CRUD_ACTIONS = [:index, :new, :create, :edit, :update, :show, :destroy]
|
40
|
+
|
41
|
+
def crud
|
42
|
+
CRUD_ACTIONS
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
CanCan::Ability.include(ActsAsArchived::CanCan)
|
47
|
+
CanCan::Ability.include(ActsAsStatused::CanCan)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
36
51
|
end
|
37
52
|
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.2.
|
4
|
+
version: 1.2.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: 2019-01-
|
11
|
+
date: 2019-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- app/models/concerns/acts_as_tokened.rb
|
53
53
|
- app/models/concerns/effective_resource.rb
|
54
54
|
- app/models/effective/access_denied.rb
|
55
|
+
- app/models/effective/action_failed.rb
|
55
56
|
- app/models/effective/attribute.rb
|
56
57
|
- app/models/effective/code_reader.rb
|
57
58
|
- app/models/effective/model_reader.rb
|