Class: Gitlab::Styles::Rubocop::Cop::CodeReuse::ActiveRecord
- Inherits:
-
RuboCop::Cop::Cop
- Object
- RuboCop::Cop::Cop
- Gitlab::Styles::Rubocop::Cop::CodeReuse::ActiveRecord
- Defined in:
- lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb
Overview
Cop that denies the use of ActiveRecord methods outside of models.
Constant Summary collapse
- MSG =
'This method can only be used inside an ActiveRecord model: ' \ 'https://gitlab.com/gitlab-org/gitlab-foss/issues/49653'
- NOT_ALLOWED =
Various methods from ActiveRecord::Querying that are denied. We exclude some generic ones such as ‘any?` and `first`, as these may lead to too many false positives, since `Array` also supports these methods.
The keys of this Hash are the denied method names. The values are booleans that indicate if the method should only be denied if any arguments are provided.
{ average: true, calculate: true, count_by_sql: true, create_with: true, distinct: false, eager_load: true, exists?: true, find_by: true, find_by!: true, find_by_sql: true, find_each: true, find_in_batches: true, find_or_create_by: true, find_or_create_by!: true, find_or_initialize_by: true, first!: false, first_or_create: true, first_or_create!: true, first_or_initialize: true, from: true, group: true, having: true, ids: false, includes: true, joins: true, lock: false, many?: false, offset: true, order: true, pluck: true, preload: true, readonly: false, references: true, reorder: true, rewhere: true, take: false, take!: false, unscope: false, where: false, with: true }.freeze
Instance Method Summary collapse
- #allowed_scopes ⇒ Object
-
#autocorrect(node) ⇒ Object
We can not auto correct code like this, as it requires manual refactoring.
- #indentation_of(node) ⇒ Object
- #on_send(node) ⇒ Object
- #surrounding_scope_of(node) ⇒ Object
Instance Method Details
#allowed_scopes ⇒ Object
122 123 124 |
# File 'lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb', line 122 def allowed_scopes @allowed_scopes ||= Set.new end |
#autocorrect(node) ⇒ Object
We can not auto correct code like this, as it requires manual refactoring. Instead, we’ll just allow the surrounding scope.
Despite this method’s presence, you should not use it. This method exists to make it possible to allow large chunks of offenses we can’t fix in the short term. If you are writing new code, follow the code reuse guidelines, instead of allowing any new offenses.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb', line 87 def autocorrect(node) scope = surrounding_scope_of(node) indent = indentation_of(scope) lambda do |corrector| # This prevents us from inserting the same enable/disable comment # for a method or block that has multiple offenses. next if allowed_scopes.include?(scope) corrector.insert_before( scope.source_range, "# rubocop: disable #{cop_name}\n#{indent}" ) corrector.insert_after( scope.source_range, "\n#{indent}# rubocop: enable #{cop_name}" ) allowed_scopes << scope end end |
#indentation_of(node) ⇒ Object
110 111 112 |
# File 'lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb', line 110 def indentation_of(node) ' ' * node.loc.expression.source_line[/\A */].length end |
#on_send(node) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb', line 64 def on_send(node) receiver = node.children[0] send_name = node.children[1] first_arg = node.children[2] return unless receiver && NOT_ALLOWED.key?(send_name) # If the rule requires an argument to be given, but none are # provided, we won't register an offense. This prevents us from # adding offenses for `project.group`, while still covering # `Project.group(:name)`. return if NOT_ALLOWED[send_name] && !first_arg add_offense(node, location: :selector) end |
#surrounding_scope_of(node) ⇒ Object
114 115 116 117 118 119 120 |
# File 'lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb', line 114 def surrounding_scope_of(node) %i[def defs block begin].each do |type| if (found = node.each_ancestor(type).first) return found end end end |