Rails

Rails/ActionFilter

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.19

-

This cop enforces the consistent use of action filter methods.

The cop is configurable and can enforce the use of the older something_filter methods or the newer something_action methods.

Examples

EnforcedStyle: action (default)

# bad
after_filter :do_stuff
append_around_filter :do_stuff
skip_after_filter :do_stuff

# good
after_action :do_stuff
append_around_action :do_stuff
skip_after_action :do_stuff

EnforcedStyle: filter

# bad
after_action :do_stuff
append_around_action :do_stuff
skip_after_action :do_stuff

# good
after_filter :do_stuff
append_around_filter :do_stuff
skip_after_filter :do_stuff

Configurable attributes

Name Default value Configurable values

EnforcedStyle

action

action, filter

Include

app/controllers/*/.rb

Array

Rails/ActiveRecordAliases

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes (Unsafe)

0.53

-

Checks that ActiveRecord aliases are not used. The direct method names are more clear and easier to read.

Examples

#bad
Book.update_attributes!(author: 'Alice')

#good
Book.update!(author: 'Alice')

Rails/ActiveRecordCallbacksOrder

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.7

-

This cop checks that Active Record callbacks are declared in the order in which they will be executed.

Examples

# bad
class Person < ApplicationRecord
  after_commit :after_commit_callback
  before_validation :before_validation_callback
end

# good
class Person < ApplicationRecord
  before_validation :before_validation_callback
  after_commit :after_commit_callback
end

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/ActiveRecordOverride

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.67

-

Checks for overriding built-in Active Record methods instead of using callbacks.

Examples

# bad
class Book < ApplicationRecord
  def save
    self.title = title.upcase!
    super
  end
end

# good
class Book < ApplicationRecord
  before_save :upcase_title

  def upcase_title
    self.title = title.upcase!
  end
end

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/ActiveSupportAliases

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.48

-

This cop checks that ActiveSupport aliases to core ruby methods are not used.

Examples

# good
'some_string'.start_with?('prefix')
'some_string'.end_with?('suffix')
[1, 2, 'a'] << 'b'
[1, 2, 'a'].unshift('b')

# bad
'some_string'.starts_with?('prefix')
'some_string'.ends_with?('suffix')
[1, 2, 'a'].append('b')
[1, 2, 'a'].prepend('b')

Rails/AfterCommitOverride

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

No

2.8

-

This cop enforces that there is only one call to after_commit (and its aliases - after_create_commit, after_update_commit, and after_destroy_commit) with the same callback name per model.

Examples

# bad
# This won't be triggered.
after_create_commit :log_action

# This will override the callback added by
# after_create_commit.
after_update_commit :log_action

# bad
# This won't be triggered.
after_commit :log_action, on: :create
# This won't be triggered.
after_update_commit :log_action
# This will override both previous callbacks.
after_commit :log_action, on: :destroy

# good
after_save_commit :log_action

# good
after_create_commit :log_create_action
after_update_commit :log_update_action

Rails/ApplicationController

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes (Unsafe)

2.4

2.5

This cop checks that controllers subclass ApplicationController.

Examples

# good
class MyController < ApplicationController
  # ...
end

# bad
class MyController < ActionController::Base
  # ...
end

Rails/ApplicationJob

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes (Unsafe)

0.49

2.5

This cop checks that jobs subclass ApplicationJob with Rails 5.0.

Examples

# good
class Rails5Job < ApplicationJob
  # ...
end

# bad
class Rails4Job < ActiveJob::Base
  # ...
end

Rails/ApplicationMailer

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes (Unsafe)

2.4

2.5

This cop checks that mailers subclass ApplicationMailer with Rails 5.0.

Examples

# good
class MyMailer < ApplicationMailer
  # ...
end

# bad
class MyMailer < ActionMailer::Base
  # ...
end

Rails/ApplicationRecord

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes (Unsafe)

0.49

2.5

This cop checks that models subclass ApplicationRecord with Rails 5.0.

Examples

# good
class Rails5Model < ApplicationRecord
  # ...
end

# bad
class Rails4Model < ActiveRecord::Base
  # ...
end

Rails/AssertNot

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.56

-

Use assert_not instead of assert !.

Examples

# bad
assert !x

# good
assert_not x

Configurable attributes

Name Default value Configurable values

Include

**/test/**/*

Array

Rails/BelongsTo

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.62

-

This cop looks for belongs_to associations where we control whether the association is required via the deprecated required option instead.

Since Rails 5, belongs_to associations are required by default and this can be controlled through the use of optional: true.

From the release notes:

belongs_to will now trigger a validation error by default if the
association is not present. You can turn this off on a
per-association basis with optional: true. Also deprecate required
option in favor of optional for belongs_to. (Pull Request)

In the case that the developer is doing required: false, we definitely want to autocorrect to optional: true.

However, without knowing whether they’ve set overridden the default value of config.active_record.belongs_to_required_by_default, we can’t say whether it’s safe to remove required: true or whether we should replace it with optional: false (or, similarly, remove a superfluous optional: false). Therefore, in the cases we’re using required: true, we’ll simply invert it to optional: false and the user can remove depending on their defaults.

Examples

# bad
class Post < ApplicationRecord
  belongs_to :blog, required: false
end

# good
class Post < ApplicationRecord
  belongs_to :blog, optional: true
end

# bad
class Post < ApplicationRecord
  belongs_to :blog, required: true
end

# good
class Post < ApplicationRecord
  belongs_to :blog, optional: false
end

Rails/Blank

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.48

0.67

This cop checks for code that can be written with simpler conditionals using Object#blank? defined by Active Support.

Interaction with Style/UnlessElse: The configuration of NotPresent will not produce an offense in the context of unless else if Style/UnlessElse is inabled. This is to prevent interference between the auto-correction of the two cops.

Examples

NilOrEmpty: true (default)

# Converts usages of `nil? || empty?` to `blank?`

# bad
foo.nil? || foo.empty?
foo == nil || foo.empty?

# good
foo.blank?

NotPresent: true (default)

# Converts usages of `!present?` to `blank?`

# bad
!foo.present?

# good
foo.blank?

UnlessPresent: true (default)

# Converts usages of `unless present?` to `if blank?`

# bad
something unless foo.present?

# good
something if foo.blank?

# bad
unless foo.present?
  something
end

# good
if foo.blank?
  something
end

# good
def blank?
  !present?
end

Configurable attributes

Name Default value Configurable values

NilOrEmpty

true

Boolean

NotPresent

true

Boolean

UnlessPresent

true

Boolean

Rails/BulkChangeTable

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.57

-

This Cop checks whether alter queries are combinable. If combinable queries are detected, it suggests to you to use change_table with bulk: true instead. This option causes the migration to generate a single ALTER TABLE statement combining multiple column alterations.

The bulk option is only supported on the MySQL and the PostgreSQL (5.2 later) adapter; thus it will automatically detect an adapter from development environment in config/database.yml when the Database option is not set. If the adapter is not mysql2 or postgresql, this Cop ignores offenses.

Examples

# bad
def change
  add_column :users, :name, :string, null: false
  add_column :users, :nickname, :string

  # ALTER TABLE `users` ADD `name` varchar(255) NOT NULL
  # ALTER TABLE `users` ADD `nickname` varchar(255)
end

# good
def change
  change_table :users, bulk: true do |t|
    t.string :name, null: false
    t.string :nickname
  end

  # ALTER TABLE `users` ADD `name` varchar(255) NOT NULL,
  #                     ADD `nickname` varchar(255)
end
# bad
def change
  change_table :users do |t|
    t.string :name, null: false
    t.string :nickname
  end
end

# good
def change
  change_table :users, bulk: true do |t|
    t.string :name, null: false
    t.string :nickname
  end
end

# good
# When you don't want to combine alter queries.
def change
  change_table :users, bulk: false do |t|
    t.string :name, null: false
    t.string :nickname
  end
end

Configurable attributes

Name Default value Configurable values

Database

<none>

mysql, postgresql

Include

db/migrate/*.rb

Array

Rails/ContentTag

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

2.6

-

This cop checks that tag is used instead of content_tag because content_tag is legacy syntax.

Allow content_tag when the first argument is a variable because content_tag(name) is simpler rather than tag.public_send(name).

Examples

# bad
content_tag(:p, 'Hello world!')
content_tag(:br)

# good
tag.p('Hello world!')
tag.br
content_tag(name, 'Hello world!')

Rails/CreateTableWithTimestamps

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.52

-

This cop checks the migration for which timestamps are not included when creating a new table. In many cases, timestamps are useful information and should be added.

Examples

# bad
create_table :users

# bad
create_table :users do |t|
  t.string :name
  t.string :email
end

# good
create_table :users do |t|
  t.string :name
  t.string :email

  t.timestamps
end

# good
create_table :users do |t|
  t.string :name
  t.string :email

  t.datetime :created_at, default: -> { 'CURRENT_TIMESTAMP' }
end

# good
create_table :users do |t|
  t.string :name
  t.string :email

  t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP' }
end

Configurable attributes

Name Default value Configurable values

Include

db/migrate/*.rb

Array

Rails/Date

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.30

0.33

This cop checks for the correct use of Date methods, such as Date.today, Date.current etc.

Using Date.today is dangerous, because it doesn’t know anything about Rails time zone. You must use Time.zone.today instead.

The cop also reports warnings when you are using to_time method, because it doesn’t know about Rails time zone either.

Two styles are supported for this cop. When EnforcedStyle is 'strict' then the Date methods today, current, yesterday, and tomorrow are prohibited and the usage of both to_time and 'to_time_in_current_zone' are reported as warning.

When EnforcedStyle is 'flexible' then only Date.today is prohibited and only to_time is reported as warning.

Examples

EnforcedStyle: strict

# bad
Date.current
Date.yesterday
Date.today
date.to_time

# good
Time.zone.today
Time.zone.today - 1.day

EnforcedStyle: flexible (default)

# bad
Date.today
date.to_time

# good
Time.zone.today
Time.zone.today - 1.day
Date.current
Date.yesterday
date.in_time_zone

Configurable attributes

Name Default value Configurable values

EnforcedStyle

flexible

strict, flexible

Rails/DefaultScope

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Disabled

Yes

No

2.7

-

This cop looks for uses of default_scope.

Examples

# bad
default_scope -> { where(hidden: false) }

# good
scope :published, -> { where(hidden: false) }

# bad
def self.default_scope
  where(hidden: false)
end

# good
def self.published
  where(hidden: false)
end

Rails/Delegate

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.21

0.50

This cop looks for delegations that could have been created automatically with the delegate method.

Safe navigation &. is ignored because Rails' allow_nil option checks not just for nil but also delegates if nil responds to the delegated method.

The EnforceForPrefixed option (defaulted to true) means that using the target object as a prefix of the method name without using the delegate method will be a violation. When set to false, this case is legal.

Examples

# bad
def bar
  foo.bar
end

# good
delegate :bar, to: :foo

# good
def bar
  foo&.bar
end

# good
private
def bar
  foo.bar
end

EnforceForPrefixed: true (default)

# bad
def foo_bar
  foo.bar
end

# good
delegate :bar, to: :foo, prefix: true

EnforceForPrefixed: false

# good
def foo_bar
  foo.bar
end

# good
delegate :bar, to: :foo, prefix: true

Configurable attributes

Name Default value Configurable values

EnforceForPrefixed

true

Boolean

Rails/DelegateAllowBlank

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.44

-

This cop looks for delegations that pass :allow_blank as an option instead of :allow_nil. :allow_blank is not a valid option to pass to ActiveSupport#delegate.

Examples

# bad
delegate :foo, to: :bar, allow_blank: true

# good
delegate :foo, to: :bar, allow_nil: true

Rails/DynamicFindBy

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.44

2.6

This cop checks dynamic find_by_* methods. Use find_by instead of dynamic method. See. https://rails.rubystyle.guide#find_by

Examples

# bad
User.find_by_name(name)
User.find_by_name_and_email(name)
User.find_by_email!(name)

# good
User.find_by(name: name)
User.find_by(name: name, email: email)
User.find_by!(email: email)

AllowedMethods: find_by_sql

# bad
User.find_by_query(users_query)

# good
User.find_by_sql(users_sql)

AllowedReceivers: Gem::Specification

# bad
Specification.find_by_name('backend').gem_dir

# good
Gem::Specification.find_by_name('backend').gem_dir

Configurable attributes

Name Default value Configurable values

Whitelist

find_by_sql

Array

AllowedMethods

find_by_sql

Array

AllowedReceivers

Gem::Specification

Array

Rails/EnumHash

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

2.3

-

This cop looks for enums written with array syntax.

When using array syntax, adding an element in a position other than the last causes all previous definitions to shift. Explicitly specifying the value for each key prevents this from happening.

Examples

# bad
enum status: [:active, :archived]

# good
enum status: { active: 0, archived: 1 }

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/EnumUniqueness

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.46

-

This cop looks for duplicate values in enum declarations.

Examples

# bad
enum status: { active: 0, archived: 0 }

# good
enum status: { active: 0, archived: 1 }

# bad
enum status: [:active, :archived, :active]

# good
enum status: [:active, :archived]

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/EnvironmentComparison

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.52

-

This cop checks that Rails.env is compared using .production?-like methods instead of equality against a string or symbol.

Examples

# bad
Rails.env == 'production'

# bad, always returns false
Rails.env == :test

# good
Rails.env.production?

Rails/Exit

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.41

-

This cop enforces that exit calls are not used within a rails app. Valid options are instead to raise an error, break, return, or some other form of stopping execution of current request.

There are two obvious cases where exit is particularly harmful:

  • Usage in library code for your application. Even though Rails will rescue from a SystemExit and continue on, unit testing that library code will result in specs exiting (potentially silently if exit(0) is used.)

  • Usage in application code outside of the web process could result in the program exiting, which could result in the code failing to run and do its job.

Examples

# bad
exit(0)

# good
raise 'a bad error has happened'

Configurable attributes

Name Default value Configurable values

Include

app//.rb, config//.rb, lib/*/.rb

Array

Exclude

lib/*/.rake

Array

Rails/FilePath

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.47

2.4

This cop is used to identify usages of file path joining process to use Rails.root.join clause. It is used to add uniformity when joining paths.

Examples

EnforcedStyle: arguments

# bad
Rails.root.join('app/models/goober')
File.join(Rails.root, 'app/models/goober')
"#{Rails.root}/app/models/goober"

# good
Rails.root.join('app', 'models', 'goober')

EnforcedStyle: slashes (default)

# bad
Rails.root.join('app', 'models', 'goober')
File.join(Rails.root, 'app/models/goober')
"#{Rails.root}/app/models/goober"

# good
Rails.root.join('app/models/goober')

Configurable attributes

Name Default value Configurable values

EnforcedStyle

slashes

slashes, arguments

Rails/FindBy

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.30

-

This cop is used to identify usages of where.first and change them to use find_by instead.

Examples

# bad
User.where(name: 'Bruce').first
User.where(name: 'Bruce').take

# good
User.find_by(name: 'Bruce')

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/FindById

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.7

-

This cop enforces that ActiveRecord#find is used instead of where.take!, find_by!, and find_by_id! to retrieve a single record by primary key when you expect it to be found.

Examples

# bad
User.where(id: id).take!
User.find_by_id!(id)
User.find_by!(id: id)

# good
User.find(id)

Rails/FindEach

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.30

-

This cop is used to identify usages of all.each and change them to use all.find_each instead.

Examples

# bad
User.all.each

# good
User.all.find_each

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/HasAndBelongsToMany

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.12

-

This cop checks for the use of the has_and_belongs_to_many macro.

Examples

# bad
# has_and_belongs_to_many :ingredients

# good
# has_many :ingredients, through: :recipe_ingredients

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/HasManyOrHasOneDependent

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.50

-

This cop looks for has_many or has_one associations that don’t specify a :dependent option. It doesn’t register an offense if :through option was specified.

Examples

# bad
class User < ActiveRecord::Base
  has_many :comments
  has_one :avatar
end

# good
class User < ActiveRecord::Base
  has_many :comments, dependent: :restrict_with_exception
  has_one :avatar, dependent: :destroy
  has_many :patients, through: :appointments
end

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/HelperInstanceVariable

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

2.0

-

This cop checks for use of the helper methods which reference instance variables.

Relying on instance variables makes it difficult to re-use helper methods.

If it seems awkward to explicitly pass in each dependent variable, consider moving the behaviour elsewhere, for example to a model, decorator or presenter.

Examples

# bad
def welcome_message
  "Hello #{@user.name}"
end

# good
def welcome_message(user)
  "Hello #{user.name}"
end

Configurable attributes

Name Default value Configurable values

Include

app/helpers/*/.rb

Array

Rails/HttpPositionalArguments

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.44

-

This cop is used to identify usages of http methods like get, post, put, patch without the usage of keyword arguments in your tests and change them to use keyword args. This cop only applies to Rails >= 5. If you are running Rails < 5 you should disable the Rails/HttpPositionalArguments cop or set your TargetRailsVersion in your .rubocop.yml file to 4.2.

Examples

# bad
get :new, { user_id: 1}

# good
get :new, params: { user_id: 1 }

Configurable attributes

Name Default value Configurable values

Include

spec//, test//

Array

Rails/HttpStatus

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.54

-

Enforces use of symbolic or numeric value to define HTTP status.

Examples

EnforcedStyle: symbolic (default)

# bad
render :foo, status: 200
render json: { foo: 'bar' }, status: 200
render plain: 'foo/bar', status: 304
redirect_to root_url, status: 301

# good
render :foo, status: :ok
render json: { foo: 'bar' }, status: :ok
render plain: 'foo/bar', status: :not_modified
redirect_to root_url, status: :moved_permanently

EnforcedStyle: numeric

# bad
render :foo, status: :ok
render json: { foo: 'bar' }, status: :not_found
render plain: 'foo/bar', status: :not_modified
redirect_to root_url, status: :moved_permanently

# good
render :foo, status: 200
render json: { foo: 'bar' }, status: 404
render plain: 'foo/bar', status: 304
redirect_to root_url, status: 301

Configurable attributes

Name Default value Configurable values

EnforcedStyle

symbolic

numeric, symbolic

Rails/IgnoredSkipActionFilterOption

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.63

-

This cop checks that if and only (or except) are not used together as options of skip_* action filter.

The if option will be ignored when if and only are used together. Similarly, the except option will be ignored when if and except are used together.

Examples

# bad
class MyPageController < ApplicationController
  skip_before_action :login_required,
    only: :show, if: :trusted_origin?
end

# good
class MyPageController < ApplicationController
  skip_before_action :login_required,
    if: -> { trusted_origin? && action_name == "show" }
end
# bad
class MyPageController < ApplicationController
  skip_before_action :login_required,
    except: :admin, if: :trusted_origin?
end

# good
class MyPageController < ApplicationController
  skip_before_action :login_required,
    if: -> { trusted_origin? && action_name != "admin" }
end

Configurable attributes

Name Default value Configurable values

Include

app/controllers/*/.rb

Array

Rails/IndexBy

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

2.5

-

This cop looks for uses of each_with_object({}) { …​ }, map { …​ }.to_h, and Hash[map { …​ }] that are transforming an enumerable into a hash where the values are the original elements. Rails provides the index_by method for this purpose.

Examples

# bad
[1, 2, 3].each_with_object({}) { |el, h| h[foo(el)] = el }
[1, 2, 3].map { |el| [foo(el), el] }.to_h
Hash[[1, 2, 3].collect { |el| [foo(el), el] }]

# good
[1, 2, 3].index_by { |el| foo(el) }

Rails/IndexWith

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

2.5

-

This cop looks for uses of each_with_object({}) { …​ }, map { …​ }.to_h, and Hash[map { …​ }] that are transforming an enumerable into a hash where the keys are the original elements. Rails provides the index_with method for this purpose.

Examples

# bad
[1, 2, 3].each_with_object({}) { |el, h| h[el] = foo(el) }
[1, 2, 3].map { |el| [el, foo(el)] }.to_h
Hash[[1, 2, 3].collect { |el| [el, foo(el)] }]

# good
[1, 2, 3].index_with { |el| foo(el) }

Rails/Inquiry

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

No

2.7

-

This cop checks that Active Support’s inquiry method is not used.

Examples

# bad - String#inquiry
ruby = 'two'.inquiry
ruby.two?

# good
ruby = 'two'
ruby == 'two'

# bad - Array#inquiry
pets = %w(cat dog).inquiry
pets.gopher?

# good
pets = %w(cat dog)
pets.include? 'cat'

Rails/InverseOf

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.52

-

This cop looks for has_(one|many) and belongs_to associations where Active Record can’t automatically determine the inverse association because of a scope or the options used. Using the blog with order scope example below, traversing the a Blog’s association in both directions with blog.posts.first.blog would cause the blog to be loaded from the database twice.

:inverse_of must be manually specified for Active Record to use the associated object in memory, or set to false to opt-out. Note that setting nil does not stop Active Record from trying to determine the inverse automatically, and is not considered a valid value for this.

Examples

# good
class Blog < ApplicationRecord
  has_many :posts
end

class Post < ApplicationRecord
  belongs_to :blog
end
# bad
class Blog < ApplicationRecord
  has_many :posts, -> { order(published_at: :desc) }
end

class Post < ApplicationRecord
  belongs_to :blog
end

# good
class Blog < ApplicationRecord
  has_many(:posts,
           -> { order(published_at: :desc) },
           inverse_of: :blog)
end

class Post < ApplicationRecord
  belongs_to :blog
end

# good
class Blog < ApplicationRecord
  with_options inverse_of: :blog do
    has_many :posts, -> { order(published_at: :desc) }
  end
end

class Post < ApplicationRecord
  belongs_to :blog
end

# good
# When you don't want to use the inverse association.
class Blog < ApplicationRecord
  has_many(:posts,
           -> { order(published_at: :desc) },
           inverse_of: false)
end
# bad
class Picture < ApplicationRecord
  belongs_to :imageable, polymorphic: true
end

class Employee < ApplicationRecord
  has_many :pictures, as: :imageable
end

class Product < ApplicationRecord
  has_many :pictures, as: :imageable
end

# good
class Picture < ApplicationRecord
  belongs_to :imageable, polymorphic: true
end

class Employee < ApplicationRecord
  has_many :pictures, as: :imageable, inverse_of: :imageable
end

class Product < ApplicationRecord
  has_many :pictures, as: :imageable, inverse_of: :imageable
end
# bad
# However, RuboCop can not detect this pattern...
class Physician < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :physician
  belongs_to :patient
end

class Patient < ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end

# good
class Physician < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :physician, inverse_of: :appointments
  belongs_to :patient, inverse_of: :appointments
end

class Patient < ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/LexicallyScopedActionFilter

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

No

No

0.52

-

This cop checks that methods specified in the filter’s only or except options are defined within the same class or module.

You can technically specify methods of superclass or methods added by mixins on the filter, but these can confuse developers. If you specify methods that are defined in other classes or modules, you should define the filter in that class or module.

If you rely on behaviour defined in the superclass actions, you must remember to invoke super in the subclass actions.

Examples

# bad
class LoginController < ApplicationController
  before_action :require_login, only: %i[index settings logout]

  def index
  end
end

# good
class LoginController < ApplicationController
  before_action :require_login, only: %i[index settings logout]

  def index
  end

  def settings
  end

  def logout
  end
end
# bad
module FooMixin
  extend ActiveSupport::Concern

  included do
    before_action proc { authenticate }, only: :foo
  end
end

# good
module FooMixin
  extend ActiveSupport::Concern

  included do
    before_action proc { authenticate }, only: :foo
  end

  def foo
    # something
  end
end
class ContentController < ApplicationController
  def update
    @content.update(content_attributes)
  end
end

class ArticlesController < ContentController
  before_action :load_article, only: [:update]

  # the cop requires this method, but it relies on behaviour defined
  # in the superclass, so needs to invoke `super`
  def update
    super
  end

  private

  def load_article
    @content = Article.find(params[:article_id])
  end
end

Configurable attributes

Name Default value Configurable values

Include

app/controllers/*/.rb

Array

Rails/LinkToBlank

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.62

-

This cop checks for calls to link_to that contain a target: '_blank' but no rel: 'noopener'. This can be a security risk as the loaded page will have control over the previous page and could change its location for phishing purposes.

The option rel: 'noreferrer' also blocks this behavior and removes the http-referrer header.

Examples

# bad
link_to 'Click here', url, target: '_blank'

# good
link_to 'Click here', url, target: '_blank', rel: 'noopener'

# good
link_to 'Click here', url, target: '_blank', rel: 'noreferrer'

Rails/MailerName

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes (Unsafe)

2.7

-

This cop enforces that mailer names end with Mailer suffix.

Without the Mailer suffix it isn’t immediately apparent what’s a mailer and which views are related to the mailer.

Examples

# bad
class User < ActionMailer::Base
end

class User < ApplicationMailer
end

# good
class UserMailer < ActionMailer::Base
end

class UserMailer < ApplicationMailer
end

Configurable attributes

Name Default value Configurable values

Include

app/mailers/*/.rb

Array

Rails/MatchRoute

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.7

-

This cop identifies places where defining routes with match can be replaced with a specific HTTP method.

Don’t use match to define any routes unless there is a need to map multiple request types among [:get, :post, :patch, :put, :delete] to a single action using the :via option.

Examples

# bad
match ':controller/:action/:id'
match 'photos/:id', to: 'photos#show', via: :get

# good
get ':controller/:action/:id'
get 'photos/:id', to: 'photos#show'
match 'photos/:id', to: 'photos#show', via: [:get, :post]
match 'photos/:id', to: 'photos#show', via: :all

Configurable attributes

Name Default value Configurable values

Include

config/routes.rb, config/routes/*/.rb

Array

Rails/NegateInclude

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.7

-

This cop enforces the use of collection.exclude?(obj) over !collection.include?(obj).

Examples

# bad
!array.include?(2)
!hash.include?(:key)

# good
array.exclude?(2)
hash.exclude?(:key)

Rails/NotNullColumn

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.43

-

This cop checks for add_column call with NOT NULL constraint in migration file.

Examples

# bad
add_column :users, :name, :string, null: false
add_reference :products, :category, null: false

# good
add_column :users, :name, :string, null: true
add_column :users, :name, :string, null: false, default: ''
add_reference :products, :category
add_reference :products, :category, null: false, default: 1

Configurable attributes

Name Default value Configurable values

Include

db/migrate/*.rb

Array

Rails/Output

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.15

0.19

This cop checks for the use of output calls like puts and print

Examples

# bad
puts 'A debug message'
pp 'A debug message'
print 'A debug message'

# good
Rails.logger.debug 'A debug message'

Configurable attributes

Name Default value Configurable values

Include

app//.rb, config//.rb, db//.rb, lib//.rb

Array

Rails/OutputSafety

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.41

-

This cop checks for the use of output safety calls like html_safe, raw, and safe_concat. These methods do not escape content. They simply return a SafeBuffer containing the content as is. Instead, use safe_join to join content and escape it and concat to concatenate content and escape it, ensuring its safety.

Examples

user_content = "<b>hi</b>"

# bad
"<p>#{user_content}</p>".html_safe
# => ActiveSupport::SafeBuffer "<p><b>hi</b></p>"

# good
content_tag(:p, user_content)
# => ActiveSupport::SafeBuffer "<p>&lt;b&gt;hi&lt;/b&gt;</p>"

# bad
out = ""
out << "<li>#{user_content}</li>"
out << "<li>#{user_content}</li>"
out.html_safe
# => ActiveSupport::SafeBuffer "<li><b>hi</b></li><li><b>hi</b></li>"

# good
out = []
out << content_tag(:li, user_content)
out << content_tag(:li, user_content)
safe_join(out)
# => ActiveSupport::SafeBuffer
#    "<li>&lt;b&gt;hi&lt;/b&gt;</li><li>&lt;b&gt;hi&lt;/b&gt;</li>"

# bad
out = "<h1>trusted content</h1>".html_safe
out.safe_concat(user_content)
# => ActiveSupport::SafeBuffer "<h1>trusted_content</h1><b>hi</b>"

# good
out = "<h1>trusted content</h1>".html_safe
out.concat(user_content)
# => ActiveSupport::SafeBuffer
#    "<h1>trusted_content</h1>&lt;b&gt;hi&lt;/b&gt;"

# safe, though maybe not good style
out = "trusted content"
result = out.concat(user_content)
# => String "trusted content<b>hi</b>"
# because when rendered in ERB the String will be escaped:
# <%= result %>
# => trusted content&lt;b&gt;hi&lt;/b&gt;

# bad
(user_content + " " + content_tag(:span, user_content)).html_safe
# => ActiveSupport::SafeBuffer "<b>hi</b> <span><b>hi</b></span>"

# good
safe_join([user_content, " ", content_tag(:span, user_content)])
# => ActiveSupport::SafeBuffer
#    "&lt;b&gt;hi&lt;/b&gt; <span>&lt;b&gt;hi&lt;/b&gt;</span>"

Rails/Pick

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

No

Yes (Unsafe)

2.6

-

This cop enforces the use of pick over pluck(…​).first.

Using pluck followed by first creates an intermediate array, which pick avoids. When called on an Active Record relation, pick adds a limit to the query so that only one value is fetched from the database.

Examples

# bad
Model.pluck(:a).first
[{ a: :b, c: :d }].pluck(:a, :b).first

# good
Model.pick(:a)
[{ a: :b, c: :d }].pick(:a, :b)

Rails/Pluck

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.7

-

This cop enforces the use of pluck over map.

pluck can be used instead of map to extract a single key from each element in an enumerable. When called on an Active Record relation, it results in a more efficient query that only selects the necessary key.

Examples

# bad
Post.published.map { |post| post[:title] }
[{ a: :b, c: :d }].collect { |el| el[:a] }

# good
Post.published.pluck(:title)
[{ a: :b, c: :d }].pluck(:a)

Rails/PluckId

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Disabled

No

Yes (Unsafe)

2.7

-

This cop enforces the use of ids over pluck(:id) and pluck(primary_key).

Examples

# bad
User.pluck(:id)
user.posts.pluck(:id)

def self.user_ids
  pluck(primary_key)
end

# good
User.ids
user.posts.ids

def self.user_ids
  ids
end

Rails/PluckInWhere

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

No

Yes (Unsafe)

2.7

2.8

This cop identifies places where pluck is used in where query methods and can be replaced with select.

Since pluck is an eager method and hits the database immediately, using select helps to avoid additional database queries.

This cop has two different enforcement modes. When the EnforcedStyle is conservative (the default) then only calls to pluck on a constant (i.e. a model class) in the where is used as offenses.

When the EnforcedStyle is aggressive then all calls to pluck in the where is used as offenses. This may lead to false positives as the cop cannot replace to select between calls to pluck on an ActiveRecord::Relation instance vs a call to pluck on an Array instance.

Examples

# bad
Post.where(user_id: User.active.pluck(:id))

# good
Post.where(user_id: User.active.select(:id))
Post.where(user_id: active_users.select(:id))

EnforcedStyle: conservative (default)

# good
Post.where(user_id: active_users.pluck(:id))

EnforcedStyle: aggressive

# bad
Post.where(user_id: active_users.pluck(:id))

Configurable attributes

Name Default value Configurable values

EnforcedStyle

conservative

conservative, aggressive

Rails/PluralizationGrammar

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.35

-

This cop checks for correct grammar when using ActiveSupport’s core extensions to the numeric classes.

Examples

# bad
3.day.ago
1.months.ago

# good
3.days.ago
1.month.ago

Rails/Presence

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.52

-

This cop checks code that can be written more easily using Object#presence defined by Active Support.

Examples

# bad
a.present? ? a : nil

# bad
!a.present? ? nil : a

# bad
a.blank? ? nil : a

# bad
!a.blank? ? a : nil

# good
a.presence
# bad
a.present? ? a : b

# bad
!a.present? ? b : a

# bad
a.blank? ? b : a

# bad
!a.blank? ? a : b

# good
a.presence || b

Rails/Present

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.48

0.67

This cop checks for code that can be written with simpler conditionals using Object#present? defined by Active Support.

Interaction with Style/UnlessElse: The configuration of NotBlank will not produce an offense in the context of unless else if Style/UnlessElse is inabled. This is to prevent interference between the auto-correction of the two cops.

Examples

NotNilAndNotEmpty: true (default)

# Converts usages of `!nil? && !empty?` to `present?`

# bad
!foo.nil? && !foo.empty?

# bad
foo != nil && !foo.empty?

# good
foo.present?

NotBlank: true (default)

# Converts usages of `!blank?` to `present?`

# bad
!foo.blank?

# bad
not foo.blank?

# good
foo.present?

UnlessBlank: true (default)

# Converts usages of `unless blank?` to `if present?`

# bad
something unless foo.blank?

# good
something if foo.present?

Configurable attributes

Name Default value Configurable values

NotNilAndNotEmpty

true

Boolean

NotBlank

true

Boolean

UnlessBlank

true

Boolean

Rails/RakeEnvironment

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

No

Yes (Unsafe)

2.4

2.6

This cop checks for Rake tasks without the :environment task dependency. The :environment task loads application code for other Rake tasks. Without it, tasks cannot make use of application code like models.

You can ignore the offense if the task satisfies at least one of the following conditions:

  • The task does not need application code.

  • The task invokes the :environment task.

Examples

# bad
task :foo do
  do_something
end

# good
task foo: :environment do
  do_something
end

Configurable attributes

Name Default value Configurable values

Include

**/Rakefile, **/*.rake

Array

Exclude

lib/capistrano/tasks/*/.rake

Array

Rails/ReadWriteAttribute

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.20

0.29

This cop checks for the use of the read_attribute or write_attribute methods and recommends square brackets instead.

If an attribute is missing from the instance (for example, when initialized by a partial select) then read_attribute will return nil, but square brackets will raise an ActiveModel::MissingAttributeError.

Explicitly raising an error in this situation is preferable, and that is why rubocop recommends using square brackets.

Examples

# bad
x = read_attribute(:attr)
write_attribute(:attr, val)

# good
x = self[:attr]
self[:attr] = val

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/RedundantAllowNil

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.67

-

Checks Rails model validations for a redundant allow_nil when allow_blank is present.

Examples

# bad
validates :x, length: { is: 5 }, allow_nil: true, allow_blank: true

# bad
validates :x, length: { is: 5 }, allow_nil: false, allow_blank: true

# bad
validates :x, length: { is: 5 }, allow_nil: false, allow_blank: false

# good
validates :x, length: { is: 5 }, allow_blank: true

# good
validates :x, length: { is: 5 }, allow_blank: false

# good
# Here, `nil` is valid but `''` is not
validates :x, length: { is: 5 }, allow_nil: true, allow_blank: false

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/RedundantForeignKey

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

2.6

-

This cop detects cases where the :foreign_key option on associations is redundant.

Examples

# bad
class Post
  has_many :comments, foreign_key: 'post_id'
end

class Comment
  belongs_to :post, foreign_key: 'post_id'
end

# good
class Post
  has_many :comments
end

class Comment
  belongs_to :author, foreign_key: 'user_id'
end

Rails/RedundantReceiverInWithOptions

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.52

-

This cop checks for redundant receiver in with_options. Receiver is implicit from Rails 4.2 or higher.

Examples

# bad
class Account < ApplicationRecord
  with_options dependent: :destroy do |assoc|
    assoc.has_many :customers
    assoc.has_many :products
    assoc.has_many :invoices
    assoc.has_many :expenses
  end
end

# good
class Account < ApplicationRecord
  with_options dependent: :destroy do
    has_many :customers
    has_many :products
    has_many :invoices
    has_many :expenses
  end
end
# bad
with_options options: false do |merger|
  merger.invoke(merger.something)
end

# good
with_options options: false do
  invoke(something)
end

# good
client = Client.new
with_options options: false do |merger|
  client.invoke(merger.something, something)
end

# ok
# When `with_options` includes a block, all scoping scenarios
# cannot be evaluated. Thus, it is ok to include the explicit
# receiver.
with_options options: false do |merger|
  merger.invoke
  with_another_method do |another_receiver|
    merger.invoke(another_receiver)
  end
end

Rails/ReflectionClassName

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.64

-

This cop checks if the value of the option class_name, in the definition of a reflection is a string.

Examples

# bad
has_many :accounts, class_name: Account
has_many :accounts, class_name: Account.name

# good
has_many :accounts, class_name: 'Account'

Rails/RefuteMethods

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.56

-

Use assert_not methods instead of refute methods.

Examples

EnforcedStyle: assert_not (default)

# bad
refute false
refute_empty [1, 2, 3]
refute_equal true, false

# good
assert_not false
assert_not_empty [1, 2, 3]
assert_not_equal true, false

EnforcedStyle: refute

# bad
assert_not false
assert_not_empty [1, 2, 3]
assert_not_equal true, false

# good
refute false
refute_empty [1, 2, 3]
refute_equal true, false

Configurable attributes

Name Default value Configurable values

EnforcedStyle

assert_not

assert_not, refute

Include

**/test/**/*

Array

Rails/RelativeDateConstant

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.48

0.59

This cop checks whether constant value isn’t relative date. Because the relative date will be evaluated only once.

Examples

# bad
class SomeClass
  EXPIRED_AT = 1.week.since
end

# good
class SomeClass
  EXPIRES = 1.week

  def self.expired_at
    EXPIRES.since
  end
end

# good
class SomeClass
  def self.expired_at
    1.week.since
  end
end

Configurable attributes

Name Default value Configurable values

AutoCorrect

false

Boolean

Rails/RenderInline

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

No

2.7

-

This cop looks for inline rendering within controller actions.

Examples

# bad
class ProductsController < ApplicationController
  def index
    render inline: "<% products.each do |p| %><p><%= p.name %></p><% end %>", type: :erb
  end
end

# good
# app/views/products/index.html.erb
# <% products.each do |p| %>
#   <p><%= p.name %></p>
# <% end %>

class ProductsController < ApplicationController
  def index
  end
end

Rails/RenderPlainText

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.7

-

This cop identifies places where render text: can be replaced with render plain:.

Examples

# bad - explicit MIME type to `text/plain`
render text: 'Ruby!', content_type: 'text/plain'

# good - short and precise
render plain: 'Ruby!'

# good - explicit MIME type not to `text/plain`
render text: 'Ruby!', content_type: 'text/html'

ContentTypeCompatibility: true (default)

# good - sets MIME type to `text/html`
render text: 'Ruby!'

ContentTypeCompatibility: false

# bad - sets MIME type to `text/html`
render text: 'Ruby!'

Configurable attributes

Name Default value Configurable values

ContentTypeCompatibility

true

Boolean

Rails/RequestReferer

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.41

-

This cop checks for consistent uses of request.referer or request.referrer, depending on the cop’s configuration.

Examples

EnforcedStyle: referer (default)

# bad
request.referrer

# good
request.referer

EnforcedStyle: referrer

# bad
request.referer

# good
request.referrer

Configurable attributes

Name Default value Configurable values

EnforcedStyle

referer

referer, referrer

Rails/ReversibleMigration

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.47

-

This cop checks whether the change method of the migration file is reversible.

Examples

# bad
def change
  change_table :users do |t|
    t.remove :name
  end
end

# good
def change
  create_table :users do |t|
    t.string :name
  end
end

# good
def change
  reversible do |dir|
    change_table :users do |t|
      dir.up do
        t.column :name, :string
      end

      dir.down do
        t.remove :name
      end
    end
  end
end
# drop_table

# bad
def change
  drop_table :users
end

# good
def change
  drop_table :users do |t|
    t.string :name
  end
end
# change_column_default

# bad
def change
  change_column_default(:suppliers, :qualification, 'new')
end

# good
def change
  change_column_default(:posts, :state, from: nil, to: "draft")
end
# remove_column

# bad
def change
  remove_column(:suppliers, :qualification)
end

# good
def change
  remove_column(:suppliers, :qualification, :string)
end
# remove_foreign_key

# bad
def change
  remove_foreign_key :accounts, column: :owner_id
end

# good
def change
  remove_foreign_key :accounts, :branches
end

# good
def change
  remove_foreign_key :accounts, to_table: :branches
end
# change_table

# bad
def change
  change_table :users do |t|
    t.remove :name
    t.change_default :authorized, 1
    t.change :price, :string
  end
end

# good
def change
  change_table :users do |t|
    t.string :name
  end
end

# good
def change
  reversible do |dir|
    change_table :users do |t|
      dir.up do
        t.change :price, :string
      end

      dir.down do
        t.change :price, :integer
      end
    end
  end
end
# remove_columns

# bad
def change
  remove_columns :users, :name, :email
end

# good
def change
  reversible do |dir|
    dir.up do
      remove_columns :users, :name, :email
    end

    dir.down do
      add_column :users, :name, :string
      add_column :users, :email, :string
    end
  end
end

# good (Rails >= 6.1, see https://github.com/rails/rails/pull/36589)
def change
  remove_columns :users, :name, :email, type: :string
end
# remove_index

# bad
def change
  remove_index :users, name: :index_users_on_email
end

# good
def change
  remove_index :users, :email
end

# good
def change
  remove_index :users, column: :email
end

Configurable attributes

Name Default value Configurable values

Include

db/migrate/*.rb

Array

Rails/SafeNavigation

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.43

-

This cop converts usages of try! to &.. It can also be configured to convert try. It will convert code to use safe navigation.

Examples

ConvertTry: false (default)

# bad
foo.try!(:bar)
foo.try!(:bar, baz)
foo.try!(:bar) { |e| e.baz }

foo.try!(:[], 0)

# good
foo.try(:bar)
foo.try(:bar, baz)
foo.try(:bar) { |e| e.baz }

foo&.bar
foo&.bar(baz)
foo&.bar { |e| e.baz }

ConvertTry: true

# bad
foo.try!(:bar)
foo.try!(:bar, baz)
foo.try!(:bar) { |e| e.baz }
foo.try(:bar)
foo.try(:bar, baz)
foo.try(:bar) { |e| e.baz }

# good
foo&.bar
foo&.bar(baz)
foo&.bar { |e| e.baz }

Configurable attributes

Name Default value Configurable values

ConvertTry

false

Boolean

Rails/SafeNavigationWithBlank

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes (Unsafe)

2.4

-

This cop checks to make sure safe navigation isn’t used with blank? in a conditional.

While the safe navigation operator is generally a good idea, when checking foo&.blank? in a conditional, foo being nil will actually do the opposite of what the author intends.

Examples

# bad
do_something if foo&.blank?
do_something unless foo&.blank?

# good
do_something if foo.blank?
do_something unless foo.blank?

Rails/SaveBang

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Disabled

Yes

Yes (Unsafe)

0.42

0.59

This cop identifies possible cases where Active Record save! or related should be used instead of save because the model might have failed to save and an exception is better than unhandled failure.

This will allow:

  • update or save calls, assigned to a variable, or used as a condition in an if/unless/case statement.

  • create calls, assigned to a variable that then has a call to persisted?, or whose return value is checked by persisted? immediately

  • calls if the result is explicitly returned from methods and blocks, or provided as arguments.

  • calls whose signature doesn’t look like an ActiveRecord persistence method.

By default it will also allow implicit returns from methods and blocks. that behavior can be turned off with AllowImplicitReturn: false.

You can permit receivers that are giving false positives with AllowedReceivers: []

Examples

# bad
user.save
user.update(name: 'Joe')
user.find_or_create_by(name: 'Joe')
user.destroy

# good
unless user.save
  # ...
end
user.save!
user.update!(name: 'Joe')
user.find_or_create_by!(name: 'Joe')
user.destroy!

user = User.find_or_create_by(name: 'Joe')
unless user.persisted?
  # ...
end

def save_user
  return user.save
end

AllowImplicitReturn: true (default)

# good
users.each { |u| u.save }

def save_user
  user.save
end

AllowImplicitReturn: false

# bad
users.each { |u| u.save }
def save_user
  user.save
end

# good
users.each { |u| u.save! }

def save_user
  user.save!
end

def save_user
  return user.save
end

AllowedReceivers: ['merchant.customers', 'Service::Mailer']

# bad
merchant.create
customers.builder.save
Mailer.create

module Service::Mailer
  self.create
end

# good
merchant.customers.create
MerchantService.merchant.customers.destroy
Service::Mailer.update(message: 'Message')
::Service::Mailer.update
Services::Service::Mailer.update(message: 'Message')
Service::Mailer::update

Configurable attributes

Name Default value Configurable values

AllowImplicitReturn

true

Boolean

AllowedReceivers

[]

Array

Rails/ScopeArgs

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.19

-

This cop checks for scope calls where it was passed a method (usually a scope) instead of a lambda/proc.

Examples

# bad
scope :something, where(something: true)

# good
scope :something, -> { where(something: true) }

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/ShortI18n

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.7

-

This cop enforces that short forms of I18n methods are used: t instead of translate and l instead of localize.

This cop has two different enforcement modes. When the EnforcedStyle is conservative (the default) then only I18n.translate and I18n.localize calls are added as offenses.

When the EnforcedStyle is aggressive then all translate and localize calls without a receiver are added as offenses.

Examples

# bad
I18n.translate :key
I18n.localize Time.now

# good
I18n.t :key
I18n.l Time.now

EnforcedStyle: conservative (default)

# good
translate :key
localize Time.now
t :key
l Time.now

EnforcedStyle: aggressive

# bad
translate :key
localize Time.now

# good
t :key
l Time.now

Configurable attributes

Name Default value Configurable values

EnforcedStyle

conservative

conservative, aggressive

Rails/SkipsModelValidations

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.47

2.7

This cop checks for the use of methods which skip validations which are listed in https://guides.rubyonrails.org/active_record_validations.html#skipping-validations

Methods may be ignored from this rule by configuring a Whitelist.

Examples

# bad
Article.first.decrement!(:view_count)
DiscussionBoard.decrement_counter(:post_count, 5)
Article.first.increment!(:view_count)
DiscussionBoard.increment_counter(:post_count, 5)
person.toggle :active
product.touch
Billing.update_all("category = 'authorized', author = 'David'")
user.update_attribute(:website, 'example.com')
user.update_columns(last_request_at: Time.current)
Post.update_counters 5, comment_count: -1, action_count: 1

# good
user.update(website: 'example.com')
FileUtils.touch('file')

Whitelist: ["touch"]

# bad
DiscussionBoard.decrement_counter(:post_count, 5)
DiscussionBoard.increment_counter(:post_count, 5)
person.toggle :active

# good
user.touch

Configurable attributes

Name Default value Configurable values

ForbiddenMethods

decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all

Array

AllowedMethods

[]

Array

Rails/TimeZone

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

No

Yes (Unsafe)

0.30

0.68

This cop checks for the use of Time methods without zone.

Built on top of Ruby on Rails style guide (https://rails.rubystyle.guide#time) and the article http://danilenko.org/2012/7/6/rails_timezones/

Two styles are supported for this cop. When EnforcedStyle is 'strict' then only use of Time.zone is allowed.

When EnforcedStyle is 'flexible' then it’s also allowed to use Time.in_time_zone.

Examples

EnforcedStyle: strict

# `strict` means that `Time` should be used with `zone`.

# bad
Time.now
Time.parse('2015-03-02 19:05:37')

# bad
Time.current
Time.at(timestamp).in_time_zone

# good
Time.zone.now
Time.zone.parse('2015-03-02 19:05:37')

EnforcedStyle: flexible (default)

# `flexible` allows usage of `in_time_zone` instead of `zone`.

# bad
Time.now
Time.parse('2015-03-02 19:05:37')

# good
Time.zone.now
Time.zone.parse('2015-03-02 19:05:37')

# good
Time.current
Time.at(timestamp).in_time_zone

Configurable attributes

Name Default value Configurable values

EnforcedStyle

flexible

strict, flexible

Rails/UniqBeforePluck

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.40

2.6

Prefer the use of distinct, before pluck instead of after.

The use of distinct before pluck is preferred because it executes within the database.

This cop has two different enforcement modes. When the EnforcedStyle is conservative (the default) then only calls to pluck on a constant (i.e. a model class) before distinct are added as offenses.

When the EnforcedStyle is aggressive then all calls to pluck before distinct are added as offenses. This may lead to false positives as the cop cannot distinguish between calls to pluck on an ActiveRecord::Relation vs a call to pluck on an ActiveRecord::Associations::CollectionProxy.

Autocorrect is disabled by default for this cop since it may generate false positives.

Examples

EnforcedStyle: conservative (default)

# bad
Model.pluck(:id).uniq

# good
Model.distinct.pluck(:id)

EnforcedStyle: aggressive

# bad
# this will return a Relation that pluck is called on
Model.where(cond: true).pluck(:id).uniq

# bad
# an association on an instance will return a CollectionProxy
instance.assoc.pluck(:id).uniq

# bad
Model.pluck(:id).uniq

# good
Model.distinct.pluck(:id)

Configurable attributes

Name Default value Configurable values

EnforcedStyle

conservative

conservative, aggressive

AutoCorrect

false

Boolean

Rails/UniqueValidationWithoutIndex

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

2.5

-

When you define a uniqueness validation in Active Record model, you also should add a unique index for the column. There are two reasons First, duplicated records may occur even if Active Record’s validation is defined. Second, it will cause slow queries. The validation executes a SELECT statement with the target column when inserting/updating a record. If the column does not have an index and the table is large, the query will be heavy.

Note that the cop does nothing if db/schema.rb does not exist.

Examples

# bad - if the schema does not have a unique index
validates :account, uniqueness: true

# good - if the schema has a unique index
validates :account, uniqueness: true

# good - even if the schema does not have a unique index
validates :account, length: { minimum: MIN_LENGTH }

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/UnknownEnv

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

No

0.51

-

This cop checks that environments called with Rails.env predicates exist. By default the cop allows three environments which Rails ships with: development, test, and production. More can be added to the Environments config parameter.

Examples

# bad
Rails.env.proudction?
Rails.env == 'proudction'

# good
Rails.env.production?
Rails.env == 'production'

Configurable attributes

Name Default value Configurable values

Environments

development, test, production

Array

Rails/Validation

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Enabled

Yes

Yes

0.9

0.41

This cop checks for the use of old-style attribute validation macros.

Examples

# bad
validates_acceptance_of :foo
validates_confirmation_of :foo
validates_exclusion_of :foo
validates_format_of :foo
validates_inclusion_of :foo
validates_length_of :foo
validates_numericality_of :foo
validates_presence_of :foo
validates_absence_of :foo
validates_size_of :foo
validates_uniqueness_of :foo

# good
validates :foo, acceptance: true
validates :foo, confirmation: true
validates :foo, exclusion: true
validates :foo, format: true
validates :foo, inclusion: true
validates :foo, length: true
validates :foo, numericality: true
validates :foo, presence: true
validates :foo, absence: true
validates :foo, size: true
validates :foo, uniqueness: true

Configurable attributes

Name Default value Configurable values

Include

app/models/*/.rb

Array

Rails/WhereExists

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.7

-

This cop enforces the use of exists?(…​) over where(…​).exists?.

Examples

# bad
User.where(name: 'john').exists?
User.where(['name = ?', 'john']).exists?
User.where('name = ?', 'john').exists?
user.posts.where(published: true).exists?

# good
User.exists?(name: 'john')
User.where('length(name) > 10').exists?
user.posts.exists?(published: true)

Rails/WhereNot

Enabled by default Safe Supports autocorrection VersionAdded VersionChanged

Pending

Yes

Yes

2.8

-

This cop identifies places where manually constructed SQL in where can be replaced with where.not(…​).

Examples

# bad
User.where('name != ?', 'Gabe')
User.where('name != :name', name: 'Gabe')
User.where('name IS NOT NULL')
User.where('name NOT IN (?)', ['john', 'jane'])
User.where('name NOT IN (:names)', names: ['john', 'jane'])

# good
User.where.not(name: 'Gabe')
User.where.not(name: nil)
User.where.not(name: ['john', 'jane'])