class RuboCop::Cop::Flexport::NewGlobalModel
This cop disallows adding new models to the `app/models` directory.
The goal is to encourage developers to put new models inside Rails Engines (or at least namespaces), where they can be more modularly isolated and ownership is clear.
Use RuboCop's standard `Exclude` file list parameter to exclude existing global model files from counting as violations for this cop.
If you have a monorepo with multiple Rails services, you may wish to set GlobalModelsPath to something more specific than `app/models` so that it only matches the main monolith service and allows global models in other, smaller services. To do this, just set GlobalModelsPath to e.g. `flexport/app/models` in your `.rubocop.yml`.
@example AllowNamespacedGlobalModels: true (default)
# When `AllowNamespacedGlobalModels` is true, the cop only forbids # additions at the top-level directory. # bad # path: app/models/my_new_global_model.rb class MyNewGlobalModel < ApplicationRecord # ... end # good # path: app/models/my_namespace/my_new_global_model.rb class MyNamespace::MyNewGlobalModel < ApplicationRecord # ... end # good # path: engines/my_engine/app/models/my_engine/my_new_engine_model.rb class MyEngine::MyNewEngineModel < ApplicationRecord # ... end
@example AllowNamespacedGlobalModels: false
# When `AllowNamespacedGlobalModels` is false, the cop forbids all # new models in this directory and its descendants. # bad # path: app/models/my_new_global_model.rb class MyNewGlobalModel < ApplicationRecord # ... end # bad # path: app/models/my_namespace/my_new_global_model.rb class MyNamespace::MyNewGlobalModel < ApplicationRecord # ... end # good # path: engines/my_engine/app/models/my_engine/my_new_engine_model.rb class MyEngine::MyNewEngineModel < ApplicationRecord # ... end
Constants
- ALLOW_NAMESPACES_MSG
- DISALLOW_NAMESPACES_MSG
Public Instance Methods
# File lib/rubocop/cop/flexport/new_global_model.rb, line 74 def investigate(processed_source) return if processed_source.blank? path = processed_source.file_path return unless global_rails_model?(path) add_offense(processed_source.ast) end
Private Instance Methods
# File lib/rubocop/cop/flexport/new_global_model.rb, line 131 def allow_namespaced_global_models cop_config['AllowNamespacedGlobalModels'] end
# File lib/rubocop/cop/flexport/new_global_model.rb, line 100 def allowed_namespace?(path) return false unless allow_namespaced_global_models parts = path.split(global_models_path) parts.last.split('/').length > 1 end
# File lib/rubocop/cop/flexport/new_global_model.rb, line 125 def global_models_path path = cop_config['GlobalModelsPath'] path += '/' unless path.end_with?('/') path end
# File lib/rubocop/cop/flexport/new_global_model.rb, line 91 def global_rails_model?(path) return false unless path.include?(global_models_path) return false if path.include?('/concerns/') return false if in_engine?(path) return false if allowed_namespace?(path) true end
# File lib/rubocop/cop/flexport/new_global_model.rb, line 107 def in_engine?(path) return true if path.include?('/engines/') # Engines model dirs are structured like: # my_engine/app/models/my_engine/my_model.rb. # We detect models whose directory structure matches # this pattern even if they aren't children of an # "/engines/" directory. parts = path.split(global_models_path) potential_engine_name = parts.last.split('/').first engine_models_path = File.join( potential_engine_name, global_models_path, potential_engine_name ) path.include?(engine_models_path) end
# File lib/rubocop/cop/flexport/new_global_model.rb, line 85 def message(_node) return ALLOW_NAMESPACES_MSG if allow_namespaced_global_models DISALLOW_NAMESPACES_MSG end