mini-lite-tool 0.0.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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/cancancan-3.6.1/cancancan.gemspec +29 -0
  3. data/cancancan-3.6.1/init.rb +3 -0
  4. data/cancancan-3.6.1/lib/cancan/ability/actions.rb +93 -0
  5. data/cancancan-3.6.1/lib/cancan/ability/rules.rb +96 -0
  6. data/cancancan-3.6.1/lib/cancan/ability/strong_parameter_support.rb +41 -0
  7. data/cancancan-3.6.1/lib/cancan/ability.rb +312 -0
  8. data/cancancan-3.6.1/lib/cancan/class_matcher.rb +30 -0
  9. data/cancancan-3.6.1/lib/cancan/conditions_matcher.rb +147 -0
  10. data/cancancan-3.6.1/lib/cancan/config.rb +101 -0
  11. data/cancancan-3.6.1/lib/cancan/controller_additions.rb +399 -0
  12. data/cancancan-3.6.1/lib/cancan/controller_resource.rb +141 -0
  13. data/cancancan-3.6.1/lib/cancan/controller_resource_builder.rb +26 -0
  14. data/cancancan-3.6.1/lib/cancan/controller_resource_finder.rb +42 -0
  15. data/cancancan-3.6.1/lib/cancan/controller_resource_loader.rb +120 -0
  16. data/cancancan-3.6.1/lib/cancan/controller_resource_name_finder.rb +23 -0
  17. data/cancancan-3.6.1/lib/cancan/controller_resource_sanitizer.rb +32 -0
  18. data/cancancan-3.6.1/lib/cancan/exceptions.rb +70 -0
  19. data/cancancan-3.6.1/lib/cancan/matchers.rb +56 -0
  20. data/cancancan-3.6.1/lib/cancan/model_adapters/abstract_adapter.rb +77 -0
  21. data/cancancan-3.6.1/lib/cancan/model_adapters/active_record_4_adapter.rb +62 -0
  22. data/cancancan-3.6.1/lib/cancan/model_adapters/active_record_5_adapter.rb +61 -0
  23. data/cancancan-3.6.1/lib/cancan/model_adapters/active_record_adapter.rb +229 -0
  24. data/cancancan-3.6.1/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
  25. data/cancancan-3.6.1/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
  26. data/cancancan-3.6.1/lib/cancan/model_adapters/default_adapter.rb +9 -0
  27. data/cancancan-3.6.1/lib/cancan/model_adapters/sti_normalizer.rb +47 -0
  28. data/cancancan-3.6.1/lib/cancan/model_adapters/strategies/base.rb +40 -0
  29. data/cancancan-3.6.1/lib/cancan/model_adapters/strategies/joined_alias_each_rule_as_exists_subquery.rb +93 -0
  30. data/cancancan-3.6.1/lib/cancan/model_adapters/strategies/joined_alias_exists_subquery.rb +31 -0
  31. data/cancancan-3.6.1/lib/cancan/model_adapters/strategies/left_join.rb +11 -0
  32. data/cancancan-3.6.1/lib/cancan/model_adapters/strategies/subquery.rb +18 -0
  33. data/cancancan-3.6.1/lib/cancan/model_additions.rb +34 -0
  34. data/cancancan-3.6.1/lib/cancan/parameter_validators.rb +9 -0
  35. data/cancancan-3.6.1/lib/cancan/relevant.rb +29 -0
  36. data/cancancan-3.6.1/lib/cancan/rule.rb +140 -0
  37. data/cancancan-3.6.1/lib/cancan/rules_compressor.rb +41 -0
  38. data/cancancan-3.6.1/lib/cancan/sti_detector.rb +12 -0
  39. data/cancancan-3.6.1/lib/cancan/unauthorized_message_resolver.rb +24 -0
  40. data/cancancan-3.6.1/lib/cancan/version.rb +5 -0
  41. data/cancancan-3.6.1/lib/cancan.rb +29 -0
  42. data/cancancan-3.6.1/lib/cancancan.rb +6 -0
  43. data/cancancan-3.6.1/lib/generators/cancan/ability/USAGE +4 -0
  44. data/cancancan-3.6.1/lib/generators/cancan/ability/ability_generator.rb +13 -0
  45. data/cancancan-3.6.1/lib/generators/cancan/ability/templates/ability.rb +32 -0
  46. data/mini-lite-tool.gemspec +11 -0
  47. metadata +85 -0
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'controller_resource_loader.rb'
4
+ module CanCan
5
+ # Handle the load and authorization controller logic
6
+ # so we don't clutter up all controllers with non-interface methods.
7
+ # This class is used internally, so you do not need to call methods directly on it.
8
+ class ControllerResource # :nodoc:
9
+ include ControllerResourceLoader
10
+
11
+ def self.add_before_action(controller_class, method, *args)
12
+ options = args.extract_options!
13
+ resource_name = args.first
14
+ before_action_method = before_callback_name(options)
15
+ controller_class.send(before_action_method, options.slice(:only, :except, :if, :unless)) do |controller|
16
+ controller.class.cancan_resource_class
17
+ .new(controller, resource_name, options.except(:only, :except, :if, :unless)).send(method)
18
+ end
19
+ end
20
+
21
+ def self.before_callback_name(options)
22
+ options.delete(:prepend) ? :prepend_before_action : :before_action
23
+ end
24
+
25
+ def initialize(controller, *args)
26
+ @controller = controller
27
+ @params = controller.params
28
+ @options = args.extract_options!
29
+ @name = args.first
30
+ end
31
+
32
+ def load_and_authorize_resource
33
+ load_resource
34
+ authorize_resource
35
+ end
36
+
37
+ def authorize_resource
38
+ return if skip?(:authorize)
39
+
40
+ @controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
41
+ end
42
+
43
+ def parent?
44
+ @options.key?(:parent) ? @options[:parent] : @name && @name != name_from_controller.to_sym
45
+ end
46
+
47
+ def skip?(behavior)
48
+ return false unless (options = @controller.class.cancan_skipper[behavior][@name])
49
+
50
+ options == {} ||
51
+ options[:except] && !action_exists_in?(options[:except]) ||
52
+ action_exists_in?(options[:only])
53
+ end
54
+
55
+ protected
56
+
57
+ # Returns the class used for this resource. This can be overridden by the :class option.
58
+ # If +false+ is passed in it will use the resource name as a symbol in which case it should
59
+ # only be used for authorization, not loading since there's no class to load through.
60
+ def resource_class
61
+ case @options[:class]
62
+ when false
63
+ name.to_sym
64
+ when nil
65
+ namespaced_name.to_s.camelize.constantize
66
+ when String
67
+ @options[:class].constantize
68
+ else
69
+ @options[:class]
70
+ end
71
+ end
72
+
73
+ def load_instance?
74
+ parent? || member_action?
75
+ end
76
+
77
+ def load_collection?
78
+ resource_base.respond_to?(:accessible_by) && !current_ability.has_block?(authorization_action, resource_class)
79
+ end
80
+
81
+ def member_action?
82
+ new_actions.include?(@params[:action].to_sym) || @options[:singleton] ||
83
+ ((@params[:id] || @params[@options[:id_param]]) &&
84
+ !collection_actions.include?(@params[:action].to_sym))
85
+ end
86
+
87
+ def resource_class_with_parent
88
+ parent_resource ? { parent_resource => resource_class } : resource_class
89
+ end
90
+
91
+ def resource_instance=(instance)
92
+ @controller.instance_variable_set("@#{instance_name}", instance)
93
+ end
94
+
95
+ def resource_instance
96
+ return unless load_instance? && @controller.instance_variable_defined?("@#{instance_name}")
97
+
98
+ @controller.instance_variable_get("@#{instance_name}")
99
+ end
100
+
101
+ def collection_instance=(instance)
102
+ @controller.instance_variable_set("@#{instance_name.to_s.pluralize}", instance)
103
+ end
104
+
105
+ def collection_instance
106
+ return unless @controller.instance_variable_defined?("@#{instance_name.to_s.pluralize}")
107
+
108
+ @controller.instance_variable_get("@#{instance_name.to_s.pluralize}")
109
+ end
110
+
111
+ def parameters_require_sanitizing?
112
+ save_actions.include?(@params[:action].to_sym) || resource_params_by_namespaced_name.present?
113
+ end
114
+
115
+ def instance_name
116
+ @options[:instance_name] || name
117
+ end
118
+
119
+ def collection_actions
120
+ [:index] + Array(@options[:collection])
121
+ end
122
+
123
+ def save_actions
124
+ %i[create update]
125
+ end
126
+
127
+ private
128
+
129
+ def action_exists_in?(options)
130
+ Array(options).include?(@params[:action].to_sym)
131
+ end
132
+
133
+ def adapter
134
+ ModelAdapters::AbstractAdapter.adapter_class(resource_class)
135
+ end
136
+
137
+ def current_ability
138
+ @controller.send(:current_ability)
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module ControllerResourceBuilder
5
+ protected
6
+
7
+ def build_resource
8
+ resource = resource_base.new(resource_params || {})
9
+ assign_attributes(resource)
10
+ end
11
+
12
+ def assign_attributes(resource)
13
+ resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
14
+ initial_attributes.each do |attr_name, value|
15
+ resource.send("#{attr_name}=", value)
16
+ end
17
+ resource
18
+ end
19
+
20
+ def initial_attributes
21
+ current_ability.attributes_for(@params[:action].to_sym, resource_class).delete_if do |key, _value|
22
+ resource_params && resource_params.include?(key)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module ControllerResourceFinder
5
+ protected
6
+
7
+ def find_resource
8
+ if @options[:singleton] && parent_resource.respond_to?(name)
9
+ parent_resource.send(name)
10
+ elsif @options[:find_by]
11
+ find_resource_using_find_by
12
+ else
13
+ adapter.find(resource_base, id_param)
14
+ end
15
+ end
16
+
17
+ def find_resource_using_find_by
18
+ find_by_dynamic_finder || find_by_find_by_finder || resource_base.send(@options[:find_by], id_param)
19
+ end
20
+
21
+ def find_by_dynamic_finder
22
+ method_name = "find_by_#{@options[:find_by]}!"
23
+ resource_base.send(method_name, id_param) if resource_base.respond_to? method_name
24
+ end
25
+
26
+ def find_by_find_by_finder
27
+ resource_base.find_by(@options[:find_by].to_sym => id_param) if resource_base.respond_to? :find_by
28
+ end
29
+
30
+ def id_param
31
+ @params[id_param_key].to_s if @params[id_param_key].present?
32
+ end
33
+
34
+ def id_param_key
35
+ if @options[:id_param]
36
+ @options[:id_param]
37
+ else
38
+ parent? ? :"#{name}_id" : :id
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'controller_resource_finder.rb'
4
+ require_relative 'controller_resource_name_finder.rb'
5
+ require_relative 'controller_resource_builder.rb'
6
+ require_relative 'controller_resource_sanitizer.rb'
7
+ module CanCan
8
+ module ControllerResourceLoader
9
+ include CanCan::ControllerResourceNameFinder
10
+ include CanCan::ControllerResourceFinder
11
+ include CanCan::ControllerResourceBuilder
12
+ include CanCan::ControllerResourceSanitizer
13
+
14
+ def load_resource
15
+ return if skip?(:load)
16
+
17
+ if load_instance?
18
+ self.resource_instance ||= load_resource_instance
19
+ elsif load_collection?
20
+ self.collection_instance ||= load_collection
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ def new_actions
27
+ %i[new create] + Array(@options[:new])
28
+ end
29
+
30
+ def resource_params_by_key(key)
31
+ return unless @options[key] && @params.key?(extract_key(@options[key]))
32
+
33
+ @params[extract_key(@options[key])]
34
+ end
35
+
36
+ def resource_params_by_namespaced_name
37
+ resource_params_by_key(:instance_name) || resource_params_by_key(:class) || (
38
+ params = @params[extract_key(namespaced_name)]
39
+ params.respond_to?(:to_h) ? params : nil)
40
+ end
41
+
42
+ def resource_params
43
+ if parameters_require_sanitizing? && params_method.present?
44
+ sanitize_parameters
45
+ else
46
+ resource_params_by_namespaced_name
47
+ end
48
+ end
49
+
50
+ def fetch_parent(name)
51
+ if @controller.instance_variable_defined? "@#{name}"
52
+ @controller.instance_variable_get("@#{name}")
53
+ elsif @controller.respond_to?(name, true)
54
+ @controller.send(name)
55
+ end
56
+ end
57
+
58
+ # The object to load this resource through.
59
+ def parent_resource
60
+ parent_name && fetch_parent(parent_name)
61
+ end
62
+
63
+ def parent_name
64
+ @options[:through] && [@options[:through]].flatten.detect { |i| fetch_parent(i) }
65
+ end
66
+
67
+ def resource_base_through_parent_resource
68
+ if @options[:singleton]
69
+ resource_class
70
+ else
71
+ parent_resource.send(@options[:through_association] || name.to_s.pluralize)
72
+ end
73
+ end
74
+
75
+ def resource_base_through
76
+ if parent_resource
77
+ resource_base_through_parent_resource
78
+ elsif @options[:shallow]
79
+ resource_class
80
+ else
81
+ # maybe this should be a record not found error instead?
82
+ raise AccessDenied.new(nil, authorization_action, resource_class)
83
+ end
84
+ end
85
+
86
+ # The object that methods (such as "find", "new" or "build") are called on.
87
+ # If the :through option is passed it will go through an association on that instance.
88
+ # If the :shallow option is passed it will use the resource_class if there's no parent
89
+ # If the :singleton option is passed it won't use the association because it needs to be handled later.
90
+ def resource_base
91
+ @options[:through] ? resource_base_through : resource_class
92
+ end
93
+
94
+ def parent_authorization_action
95
+ @options[:parent_action] || :show
96
+ end
97
+
98
+ def authorization_action
99
+ parent? ? parent_authorization_action : @params[:action].to_sym
100
+ end
101
+
102
+ def load_collection
103
+ resource_base.accessible_by(current_ability, authorization_action)
104
+ end
105
+
106
+ def load_resource_instance
107
+ if !parent? && new_actions.include?(@params[:action].to_sym)
108
+ build_resource
109
+ elsif id_param || @options[:singleton]
110
+ find_resource
111
+ end
112
+ end
113
+
114
+ private
115
+
116
+ def extract_key(value)
117
+ value.to_s.underscore.tr('/', '_')
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module ControllerResourceNameFinder
5
+ protected
6
+
7
+ def name_from_controller
8
+ @params[:controller].split('/').last.singularize
9
+ end
10
+
11
+ def namespaced_name
12
+ [namespace, name].join('/').singularize.camelize.safe_constantize || name
13
+ end
14
+
15
+ def name
16
+ @name || name_from_controller
17
+ end
18
+
19
+ def namespace
20
+ @params[:controller].split('/')[0..-2]
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module ControllerResourceSanitizer
5
+ protected
6
+
7
+ def sanitize_parameters
8
+ case params_method
9
+ when Symbol
10
+ @controller.send(params_method)
11
+ when String
12
+ @controller.instance_eval(params_method)
13
+ when Proc
14
+ params_method.call(@controller)
15
+ end
16
+ end
17
+
18
+ def params_methods
19
+ methods = ["#{@params[:action]}_params".to_sym, "#{name}_params".to_sym, :resource_params]
20
+ methods.unshift(@options[:param_method]) if @options[:param_method].present?
21
+ methods
22
+ end
23
+
24
+ def params_method
25
+ params_methods.each do |method|
26
+ return method if (method.is_a?(Symbol) && @controller.respond_to?(method, true)) ||
27
+ method.is_a?(String) || method.is_a?(Proc)
28
+ end
29
+ nil
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ # A general CanCan exception
5
+ class Error < StandardError; end
6
+
7
+ # Raised when behavior is not implemented, usually used in an abstract class.
8
+ class NotImplemented < Error; end
9
+
10
+ # Raised when removed code is called, an alternative solution is provided in message.
11
+ class ImplementationRemoved < Error; end
12
+
13
+ # Raised when using check_authorization without calling authorize!
14
+ class AuthorizationNotPerformed < Error; end
15
+
16
+ # Raised when a rule is created with both a block and a hash of conditions
17
+ class BlockAndConditionsError < Error; end
18
+
19
+ # Raised when an unexpected argument is passed as an attribute
20
+ class AttributeArgumentError < Error; end
21
+
22
+ # Raised when using a wrong association name
23
+ class WrongAssociationName < Error; end
24
+
25
+ # This error is raised when a user isn't allowed to access a given controller action.
26
+ # This usually happens within a call to ControllerAdditions#authorize! but can be
27
+ # raised manually.
28
+ #
29
+ # raise CanCan::AccessDenied.new("Not authorized!", :read, Article)
30
+ #
31
+ # The passed message, action, and subject are optional and can later be retrieved when
32
+ # rescuing from the exception.
33
+ #
34
+ # exception.message # => "Not authorized!"
35
+ # exception.action # => :read
36
+ # exception.subject # => Article
37
+ #
38
+ # If the message is not specified (or is nil) it will default to "You are not authorized
39
+ # to access this page." This default can be overridden by setting default_message.
40
+ #
41
+ # exception.default_message = "Default error message"
42
+ # exception.message # => "Default error message"
43
+ #
44
+ # See ControllerAdditions#authorize! for more information on rescuing from this exception
45
+ # and customizing the message using I18n.
46
+ class AccessDenied < Error
47
+ attr_reader :action, :subject, :conditions
48
+ attr_writer :default_message
49
+
50
+ def initialize(message = nil, action = nil, subject = nil, conditions = nil)
51
+ @message = message
52
+ @action = action
53
+ @subject = subject
54
+ @conditions = conditions
55
+ @default_message = I18n.t(:"unauthorized.default", default: 'You are not authorized to access this page.')
56
+ end
57
+
58
+ def to_s
59
+ @message || @default_message
60
+ end
61
+
62
+ def inspect
63
+ details = %i[action subject conditions message].map do |attribute|
64
+ value = instance_variable_get "@#{attribute}"
65
+ "#{attribute}: #{value.inspect}" if value.present?
66
+ end.compact.join(', ')
67
+ "#<#{self.class.name} #{details}>"
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ rspec_module = defined?(RSpec::Core) ? 'RSpec' : 'Spec' # RSpec 1 compatability
4
+
5
+ if rspec_module == 'RSpec'
6
+ require 'rspec/core'
7
+ require 'rspec/expectations'
8
+ else
9
+ ActiveSupport::Deprecation.warn('RSpec < 3 will not be supported in the CanCanCan >= 2.0.0')
10
+ end
11
+
12
+ Kernel.const_get(rspec_module)::Matchers.define :be_able_to do |*args|
13
+ match do |ability|
14
+ actions = args.first
15
+ if actions.is_a? Array
16
+ if actions.empty?
17
+ false
18
+ else
19
+ actions.all? { |action| ability.can?(action, *args[1..-1]) }
20
+ end
21
+ else
22
+ ability.can?(*args)
23
+ end
24
+ end
25
+
26
+ # Check that RSpec is < 2.99
27
+ if !respond_to?(:failure_message) && respond_to?(:failure_message_for_should)
28
+ alias_method :failure_message, :failure_message_for_should
29
+ end
30
+
31
+ if !respond_to?(:failure_message_when_negated) && respond_to?(:failure_message_for_should_not)
32
+ alias_method :failure_message_when_negated, :failure_message_for_should_not
33
+ end
34
+
35
+ failure_message do
36
+ resource = args[1]
37
+ if resource.instance_of?(Class)
38
+ "expected to be able to #{args.map(&:to_s).join(' ')}"
39
+ else
40
+ "expected to be able to #{args.map(&:inspect).join(' ')}"
41
+ end
42
+ end
43
+
44
+ failure_message_when_negated do
45
+ resource = args[1]
46
+ if resource.instance_of?(Class)
47
+ "expected not to be able to #{args.map(&:to_s).join(' ')}"
48
+ else
49
+ "expected not to be able to #{args.map(&:inspect).join(' ')}"
50
+ end
51
+ end
52
+
53
+ description do
54
+ "be able to #{args.map(&:to_s).join(' ')}"
55
+ end
56
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module ModelAdapters
5
+ class AbstractAdapter
6
+ attr_reader :model_class
7
+
8
+ def self.inherited(subclass)
9
+ @subclasses ||= []
10
+ @subclasses.insert(0, subclass)
11
+ end
12
+
13
+ def self.adapter_class(model_class)
14
+ @subclasses.detect { |subclass| subclass.for_class?(model_class) } || DefaultAdapter
15
+ end
16
+
17
+ # Used to determine if the given adapter should be used for the passed in class.
18
+ def self.for_class?(_member_class)
19
+ false # override in subclass
20
+ end
21
+
22
+ # Override if you need custom find behavior
23
+ def self.find(model_class, id)
24
+ model_class.find(id)
25
+ end
26
+
27
+ # Used to determine if this model adapter will override the matching behavior for a hash of conditions.
28
+ # If this returns true then matches_conditions_hash? will be called. See Rule#matches_conditions_hash
29
+ def self.override_conditions_hash_matching?(_subject, _conditions)
30
+ false
31
+ end
32
+
33
+ # Override if override_conditions_hash_matching? returns true
34
+ def self.matches_conditions_hash?(_subject, _conditions)
35
+ raise NotImplemented, 'This model adapter does not support matching on a conditions hash.'
36
+ end
37
+
38
+ # Override if parent condition could be under a different key in conditions
39
+ def self.parent_condition_name(parent, _child)
40
+ parent.class.name.downcase.to_sym
41
+ end
42
+
43
+ # Used above override_conditions_hash_matching to determine if this model adapter will override the
44
+ # matching behavior for nested subject.
45
+ # If this returns true then nested_subject_matches_conditions? will be called.
46
+ def self.override_nested_subject_conditions_matching?(_parent, _child, _all_conditions)
47
+ false
48
+ end
49
+
50
+ # Override if override_nested_subject_conditions_matching? returns true
51
+ def self.nested_subject_matches_conditions?(_parent, _child, _all_conditions)
52
+ raise NotImplemented, 'This model adapter does not support matching on a nested subject.'
53
+ end
54
+
55
+ # Used to determine if this model adapter will override the matching behavior for a specific condition.
56
+ # If this returns true then matches_condition? will be called. See Rule#matches_conditions_hash
57
+ def self.override_condition_matching?(_subject, _name, _value)
58
+ false
59
+ end
60
+
61
+ # Override if override_condition_matching? returns true
62
+ def self.matches_condition?(_subject, _name, _value)
63
+ raise NotImplemented, 'This model adapter does not support matching on a specific condition.'
64
+ end
65
+
66
+ def initialize(model_class, rules)
67
+ @model_class = model_class
68
+ @rules = rules
69
+ end
70
+
71
+ def database_records
72
+ # This should be overridden in a subclass to return records which match @rules
73
+ raise NotImplemented, 'This model adapter does not support fetching records from the database.'
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module ModelAdapters
5
+ class ActiveRecord4Adapter < ActiveRecordAdapter
6
+ AbstractAdapter.inherited(self)
7
+
8
+ class << self
9
+ def for_class?(model_class)
10
+ version_lower?('5.0.0') && model_class <= ActiveRecord::Base
11
+ end
12
+
13
+ def override_condition_matching?(subject, name, _value)
14
+ subject.class.defined_enums.include?(name.to_s)
15
+ end
16
+
17
+ def matches_condition?(subject, name, value)
18
+ # Get the mapping from enum strings to values.
19
+ enum = subject.class.send(name.to_s.pluralize)
20
+ # Get the value of the attribute as an integer.
21
+ attribute = enum[subject.send(name)]
22
+ # Check to see if the value matches the condition.
23
+ if value.is_a?(Enumerable)
24
+ value.include? attribute
25
+ else
26
+ attribute == value
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # As of rails 4, `includes()` no longer causes active record to
34
+ # look inside the where clause to decide to outer join tables
35
+ # you're using in the where. Instead, `references()` is required
36
+ # in addition to `includes()` to force the outer join.
37
+ def build_joins_relation(relation, *_where_conditions)
38
+ relation.includes(joins).references(joins)
39
+ end
40
+
41
+ # Rails 4.2 deprecates `sanitize_sql_hash_for_conditions`
42
+ def sanitize_sql(conditions)
43
+ if self.class.version_greater_or_equal?('4.2.0') && conditions.is_a?(Hash)
44
+ sanitize_sql_activerecord4(conditions)
45
+ else
46
+ @model_class.send(:sanitize_sql, conditions)
47
+ end
48
+ end
49
+
50
+ def sanitize_sql_activerecord4(conditions)
51
+ table = Arel::Table.new(@model_class.send(:table_name))
52
+
53
+ conditions = ActiveRecord::PredicateBuilder.resolve_column_aliases @model_class, conditions
54
+ conditions = @model_class.send(:expand_hash_conditions_for_aggregates, conditions)
55
+
56
+ ActiveRecord::PredicateBuilder.build_from_hash(@model_class, conditions, table).map do |b|
57
+ @model_class.send(:connection).visitor.compile b
58
+ end.join(' AND ')
59
+ end
60
+ end
61
+ end
62
+ end