0.0
The project is in a healthy, maintained state
A collection of custom RuboCop cops for personal use, including i18n best practices.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 1.72.0
 Project Readme

RuboCop Asjer

Custom RuboCop cops: enforce i18n best practices and code quality standards.

Installation

Add to your application's Gemfile:

gem 'rubocop-asjer', require: false

Then run:

bundle install

Usage

Add to your .rubocop.yml:

plugins:
  - rubocop-asjer

Note: The plugins directive requires RuboCop 1.72+. For older versions, use require: rubocop-asjer instead.

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
end

By 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
    - serialize

Asjer/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 AllowedConstants and constants the migration defines may be referenced;
  • calls on block variables such as t.string and direction.up are fine.
  • send, public_send and eval-style calls are rejected on any receiver except a block variable.
  • self may 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_status

By 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 gem

AllowedMethods 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_visit

MethodNames 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.