RuboCop Asjer
Custom RuboCop cops: enforce i18n best practices and code quality standards.
Installation
Add to your application's Gemfile:
gem 'rubocop-asjer', require: falseThen run:
bundle installUsage
Add to your .rubocop.yml:
plugins:
- rubocop-asjerNote: The
pluginsdirective requires RuboCop 1.72+. For older versions, userequire: rubocop-asjerinstead.
Available Cops
Asjer/NoDefaultTranslation
Checks for translation calls that use the default: option. Using default: bypasses the locale system and can lead to inconsistencies.
# bad
t('some.key', default: 'fallback text')
I18n.t('some.key', default: 'fallback')
I18n.translate('some.key', default: t('other.key'))
# good
t('some.key')
I18n.t('some.key')Asjer/RailsClassOrder
Enforces consistent ordering of declarative methods in Rails models. Methods are grouped into three categories: associations, callbacks, and others. Groups are separated by blank lines.
Supports autocorrect with rubocop -a or rubocop -A.
# bad
class User < ApplicationRecord
belongs_to :plan
validate :validate_name
after_create :after_create_1
has_many :messages
attr_readonly :email
after_create :after_create_2
belongs_to :role
before_create :set_name
end
# good
class User < ApplicationRecord
belongs_to :plan
belongs_to :role
has_many :messages
validate :validate_name
before_create :set_name
after_create :after_create_1
after_create :after_create_2
attr_readonly :email
endBy default, this cop only runs on files matching app/models/**/*.rb. The method lists are fully configurable:
Asjer/RailsClassOrder:
Associations:
- belongs_to
- has_many
- has_one
- has_and_belongs_to_many
Callbacks:
- after_initialize
- after_find
# ... (see config/default.yml for full list)
Others:
- attr_readonly
- serializeAsjer/MigrationSchemaOnly
Allows only schema statements in Rails migrations. Raw SQL, model calls and other data changes skip validations and callbacks, are often irreversible, and belong in a maintenance task.
The cop uses an allowlist rather than a list of forbidden methods, so new raw-SQL routes are rejected automatically. Inside an ActiveRecord::Migration class:
- implicit-receiver calls must be schema statements (
AllowedMethods) or methods the migration defines itself; - only
AllowedConstantsand constants the migration defines may be referenced; - calls on block variables such as
t.stringanddirection.upare fine. -
send,public_sendandeval-style calls are rejected on any receiver except a block variable. -
selfmay only be used as a direct receiver; assigning or passing it would hide calls from the check.
The cop recognizes classes that inherit from ActiveRecord::Migration[x.y], ActiveRecord::Migration or ActiveRecord::Migration::Current; migrations with a custom base class are not checked.
Check constraints and expression indexes stay allowed: they keep the database consistent alongside model validations, which update_all, update_column and insert_all skip. change_column and t.change with using: are rejected because that is always a SQL cast, and so is the replacement value of change_column_null, which updates existing rows.
# bad
execute "UPDATE bookings SET source = 'web'"
select_value('SELECT 1')
connection.exec_query('SELECT 1')
send(:execute, 'SELECT 1')
Booking.where(source: nil).update_all(source: 'web')
add_index :bookings, Arel.sql('lower(code)')
change_column :bookings, :date, :date, using: 'date::date'
# good
create_table :examples do |t|
t.string :status, null: false
end
add_index :examples, 'lower(status)'
add_index :examples, :status, using: :gin, opclass: :gin_trgm_ops
add_check_constraint :examples, "status IN ('open', 'closed')", name: :examples_statusBy default, this cop runs on db/migrate/**/*.rb. To adopt it in an existing project without rewriting migrations that have already run, set StartAfter to the version of the latest existing migration; migrations up to and including that version are skipped:
Asjer/MigrationSchemaOnly:
StartAfter: 20261014120000
AllowedConstants:
- ActiveRecord::IrreversibleMigration
- Rails
- Pay::Adapter # e.g. for migrations generated by a gemAllowedMethods replaces the default list of schema statements; see config/default.yml.
Asjer/ExplicitMigrationVersionInSpec
Requires migration specs to run migrations to an explicit version. rollback, forward and migrate without a version (or with nil) move relative to the latest migration, so the spec breaks as soon as anyone adds an unrelated migration.
# bad
connection.pool.migration_context.rollback(1)
migration_context.forward
migration_context.migrate
# good
connection.pool.migration_context.run(:down, 20261012170000)
migration_context.migrate(20261012170000)By default, this cop runs on spec/migrations/**/*_spec.rb.
Asjer/SystemSpecLoginAs
Requires unqualified login_as calls in system specs to be replaced with an application-provided helper such as sign_in_and_visit(user, path). Warden's handoff applies to whichever request reaches the app server next, not necessarily the browser's intended visit.
Every matching call is reported, including calls in before blocks, whether a visit follows immediately, later, or not at all. Calls with an explicit receiver, such as foo.login_as(user), are outside this cop's scope.
# bad
login_as(user)
visit dashboard_path
before do
login_as(user)
end
# good
sign_in_and_visit(user, dashboard_path)By default, this cop only runs on spec/system/**/*.rb and is Enabled: pending. Opt in explicitly (or enable new cops with AllCops/NewCops: enable):
Asjer/SystemSpecLoginAs:
Enabled: true
Include:
- 'spec/system/**/*.rb'
MethodNames:
- login_as
PreferredHelper: sign_in_and_visitMethodNames replaces the default list of methods to flag; PreferredHelper changes the helper named in the offense message. Define that helper in your application's system-spec support; this gem does not provide it.
No autocorrect: the cop cannot infer the destination path or safely move authentication out of a before block.
Development
After checking out the repo, run bin/setup to install dependencies. Then, run bundle exec rspec to run the tests.
To install this gem onto your local machine, run bundle exec rake install.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/asjer/rubocop-asjer.
License
The gem is available as open source under the terms of the MIT License.