Class: RuboCop::Cop::Rails::ActiveSupportOnLoad

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector, TargetRailsVersion
Defined in:
lib/rubocop/cop/rails/active_support_on_load.rb

Overview

Checks for Rails framework classes that are patched directly instead of using Active Support load hooks. Direct patching forcibly loads the framework referenced, using hooks defers loading until it's actually needed.

Examples:


# bad
ActiveRecord::Base.include(MyClass)

# good
ActiveSupport.on_load(:active_record) { include MyClass }

Constant Summary collapse

MSG =
'Use `%<prefer>s` instead of `%<current>s`.'
RESTRICT_ON_SEND =
%i[prepend include extend].freeze
LOAD_HOOKS =
{
  'ActionCable' => 'action_cable',
  'ActionCable::Channel::Base' => 'action_cable_channel',
  'ActionCable::Connection::Base' => 'action_cable_connection',
  'ActionCable::Connection::TestCase' => 'action_cable_connection_test_case',
  'ActionController::API' => 'action_controller',
  'ActionController::Base' => 'action_controller',
  'ActionController::TestCase' => 'action_controller_test_case',
  'ActionDispatch::IntegrationTest' => 'action_dispatch_integration_test',
  'ActionDispatch::Request' => 'action_dispatch_request',
  'ActionDispatch::Response' => 'action_dispatch_response',
  'ActionDispatch::SystemTestCase' => 'action_dispatch_system_test_case',
  'ActionMailbox::Base' => 'action_mailbox',
  'ActionMailbox::InboundEmail' => 'action_mailbox_inbound_email',
  'ActionMailbox::Record' => 'action_mailbox_record',
  'ActionMailbox::TestCase' => 'action_mailbox_test_case',
  'ActionMailer::Base' => 'action_mailer',
  'ActionMailer::TestCase' => 'action_mailer_test_case',
  'ActionText::Content' => 'action_text_content',
  'ActionText::Record' => 'action_text_record',
  'ActionText::RichText' => 'action_text_rich_text',
  'ActionView::Base' => 'action_view',
  'ActionView::TestCase' => 'action_view_test_case',
  'ActiveJob::Base' => 'active_job',
  'ActiveJob::TestCase' => 'active_job_test_case',
  'ActiveRecord::Base' => 'active_record',
  'ActiveStorage::Attachment' => 'active_storage_attachment',
  'ActiveStorage::Blob' => 'active_storage_blob',
  'ActiveStorage::Record' => 'active_storage_record',
  'ActiveStorage::VariantRecord' => 'active_storage_variant_record',
  'ActiveSupport::TestCase' => 'active_support_test_case'
}.freeze
RAILS_5_2_LOAD_HOOKS =
{
  'ActiveRecord::ConnectionAdapters::SQLite3Adapter' => 'active_record_sqlite3adapter'
}.freeze
RAILS_7_1_LOAD_HOOKS =
{
  'ActiveRecord::TestFixtures' => 'active_record_fixtures',
  'ActiveModel::Model' => 'active_model',
  'ActionText::EncryptedRichText' => 'action_text_encrypted_rich_text',
  'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter' => 'active_record_postgresqladapter',
  'ActiveRecord::ConnectionAdapters::Mysql2Adapter' => 'active_record_mysql2adapter',
  'ActiveRecord::ConnectionAdapters::TrilogyAdapter' => 'active_record_trilogyadapter'
}.freeze

Constants included from TargetRailsVersion

TargetRailsVersion::DEFAULT_RAILS_VERSION, TargetRailsVersion::TARGET_GEM_NAME, TargetRailsVersion::USES_REQUIRES_GEM_API

Instance Method Summary collapse

Methods included from TargetRailsVersion

extended, minimum_target_rails_version, resolve, support_target_rails_version?

Instance Method Details

#hook_for_const(const_name) ⇒ Object



82
83
84
85
86
87
# File 'lib/rubocop/cop/rails/active_support_on_load.rb', line 82

def hook_for_const(const_name)
  hook = LOAD_HOOKS[const_name]
  hook ||= RAILS_5_2_LOAD_HOOKS[const_name] if target_rails_version >= 5.2
  hook ||= RAILS_7_1_LOAD_HOOKS[const_name] if target_rails_version >= 7.1
  hook
end

#on_send(node) ⇒ Object



72
73
74
75
76
77
78
79
80
# File 'lib/rubocop/cop/rails/active_support_on_load.rb', line 72

def on_send(node)
  receiver, method, arguments = *node # rubocop:disable InternalAffairs/NodeDestructuring
  return unless arguments && (hook = hook_for_const(receiver&.const_name))

  preferred = "ActiveSupport.on_load(:#{hook}) { #{method} #{arguments.source} }"
  add_offense(node, message: format(MSG, prefer: preferred, current: node.source)) do |corrector|
    corrector.replace(node, preferred)
  end
end