Rails
Rails/ActionControllerFlashBeforeRender
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.16 |
- |
Using flash
assignment before render
in Rails controllers will persist the message for too long.
Check https://guides.rubyonrails.org/action_controller_overview.html#flash-now
Rails/ActionControllerTestCase
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.14 |
- |
Using ActionController::TestCase
is discouraged and should be replaced by
ActionDispatch::IntegrationTest
. Controller tests are too close to the
internals of a controller whereas integration tests mimic the browser/user.
Safety
This cop’s autocorrection is unsafe because the API of each test case class is different. Make sure to update each test of your controller test cases after changing the superclass.
Rails/ActionFilter
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
Always |
0.19 |
2.22 |
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.
This cop is deprecated. Because the *_filter methods were removed in Rails 4.2,
and that Rails version is no longer supported by RuboCop Rails. This cop will be removed in RuboCop Rails 3.0.
|
Rails/ActionOrder
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.17 |
- |
Enforces consistent ordering of the standard Rails RESTful controller actions.
The cop is configurable and can enforce any ordering of the standard actions.
All other methods are ignored. So, the actions specified in ExpectedOrder
should be
defined before actions not specified.
Rails/ActionOrder:
ExpectedOrder:
- index
- show
- new
- edit
- create
- update
- destroy
Rails/ActiveRecordAliases
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.53 |
- |
Checks that ActiveRecord aliases are not used. The direct method names are more clear and easier to read.
Rails/ActiveRecordCallbacksOrder
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.7 |
- |
Checks that Active Record callbacks are declared in the order in which they will be executed.
Rails/ActiveRecordOverride
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.67 |
2.18 |
Checks for overriding built-in Active Record methods instead of using callbacks.
Rails/ActiveSupportAliases
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.48 |
- |
Checks that ActiveSupport aliases to core ruby methods are not used.
Rails/ActiveSupportOnLoad
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.16 |
2.24 |
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.
Safety
While using lazy load hooks is recommended, it changes the order in which is code is loaded and may reveal load order dependency bugs.
Rails/AddColumnIndex
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.11 |
2.20 |
Checks for migrations using add_column
that have an index
key. add_column
does not accept index
, but also does not raise an
error for extra keys, so it is possible to mistakenly add the key without
realizing it will not actually add an index.
Rails/AfterCommitOverride
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.8 |
- |
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 | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
2.4 |
2.5 |
Checks that controllers subclass ApplicationController
.
Rails/ApplicationJob
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.49 |
2.5 |
Checks that jobs subclass ApplicationJob
with Rails 5.0.
Rails/ApplicationMailer
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
2.4 |
2.5 |
Checks that mailers subclass ApplicationMailer
with Rails 5.0.
Rails/ApplicationRecord
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.49 |
2.26 |
Checks that models subclass ApplicationRecord
with Rails 5.0.
It is a common practice to define models inside migrations in order to retain forward compatibility by avoiding loading any application code. And so migration files are excluded by default for this cop.
Safety
This cop’s autocorrection is unsafe because it may let the logic from ApplicationRecord
sneak into an Active Record model that is not purposed to inherit logic common among other
Active Record models.
Rails/ArelStar
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
2.9 |
- |
Prevents usage of "*"
on an Arel::Table column reference.
Using arel_table[""]
causes the outputted string to be a literal
quoted asterisk (e.g. <tt>`my_model`.</tt>). This causes the
database to look for a column named <tt>`
</tt> (or `"
") as opposed
to expanding the column list as one would likely expect.
Rails/AttributeDefaultBlockValue
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.9 |
- |
Looks for attribute
class methods that specify a :default
option
which value is an array, string literal or method call without a block.
It will accept all other values, such as string, symbol, integer and float literals
as well as constants.
Examples
# bad
class User < ApplicationRecord
attribute :confirmed_at, :datetime, default: Time.zone.now
end
# good
class User < ApplicationRecord
attribute :confirmed_at, :datetime, default: -> { Time.zone.now }
end
# bad
class User < ApplicationRecord
attribute :roles, :string, array: true, default: []
end
# good
class User < ApplicationRecord
attribute :roles, :string, array: true, default: -> { [] }
end
# bad
class User < ApplicationRecord
attribute :configuration, default: {}
end
# good
class User < ApplicationRecord
attribute :configuration, default: -> { {} }
end
# good
class User < ApplicationRecord
attribute :role, :string, default: :customer
end
# good
class User < ApplicationRecord
attribute :activated, :boolean, default: false
end
# good
class User < ApplicationRecord
attribute :login_count, :integer, default: 0
end
# good
class User < ApplicationRecord
FOO = 123
attribute :custom_attribute, :integer, default: FOO
end
Rails/BelongsTo
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.62 |
- |
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 | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.48 |
2.10 |
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 enabled. This is
to prevent interference between the autocorrection of the two cops.
Safety
This cop is unsafe autocorrection, because ' '.empty?
returns false,
but ' '.blank?
returns true. Therefore, autocorrection is not compatible
if the receiver is a non-empty blank string, tab, or newline meta characters.
Rails/BulkChangeTable
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.57 |
2.20 |
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
or the environment variable DATABASE_URL
when the Database
option is not set.
If the adapter is not mysql2
, trilogy
, postgresql
, or postgis
,
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
Rails/CompactBlank
Required Rails version: 6.1 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.13 |
- |
Checks if collection can be blank-compacted with compact_blank
.
Safety
It is unsafe by default because false positives may occur in the blank check of block arguments to the receiver object.
For example, [[1, 2], [3, nil]].reject { |first, second| second.blank? }
and
[[1, 2], [3, nil]].compact_blank
are not compatible. The same is true for blank?
.
This will work fine when the receiver is a hash object.
And compact_blank!
has different implementations for Array
, Hash
, and
ActionController::Parameters
.
Array#compact_blank!
, Hash#compact_blank!
are equivalent to delete_if(&:blank?)
.
If the cop makes a mistake, autocorrected code may get unexpected behavior.
Examples
# bad
collection.reject(&:blank?)
collection.reject { |_k, v| v.blank? }
collection.select(&:present?)
collection.select { |_k, v| v.present? }
collection.filter(&:present?)
collection.filter { |_k, v| v.present? }
# good
collection.compact_blank
# bad
collection.delete_if(&:blank?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
collection.delete_if { |_k, v| v.blank? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
collection.keep_if(&:present?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
collection.keep_if { |_k, v| v.present? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
# good
collection.compact_blank!
Rails/ContentTag
Required Rails version: 5.1 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
2.6 |
2.12 |
Checks legacy syntax usage of tag
Allow tag when the first argument is a variable because
tag(name) is simpler rather than tag.public_send(name) .
And this cop will be renamed to something like LegacyTag in the future. (e.g. RuboCop Rails 3.0)
|
Examples
# bad
tag(:p)
tag(:br, class: 'classname')
# good
tag.p
tag.br(class: 'classname')
tag(name, class: 'classname')
Rails/CreateTableWithTimestamps
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.52 |
2.20 |
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.
Allow timestamps not written when id: false because this emphasizes respecting
user’s editing intentions.
|
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
# good
create_table :users, articles, id: false do |t|
t.integer :user_id
t.integer :article_id
end
Rails/DangerousColumnNames
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.21 |
- |
Avoid dangerous column names.
Some column names are considered dangerous because they would overwrite methods already defined.
Rails/Date
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.30 |
2.11 |
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 you can set a warning for to_time
with AllowToTime: false
.
AllowToTime
is true
by default to prevent false positive on DateTime
object.
Rails/DefaultScope
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
2.7 |
- |
Looks for uses of default_scope
.
Rails/Delegate
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.21 |
0.50 |
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.
Rails/DelegateAllowBlank
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.44 |
- |
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.
Rails/DeprecatedActiveModelErrorsMethods
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.14 |
2.18 |
Checks direct manipulation of ActiveModel#errors as hash. These operations are deprecated in Rails 6.1 and will not work in Rails 7.
Safety
This cop is unsafe because it can report errors
manipulation on non-ActiveModel,
which is obviously valid.
The cop has no way of knowing whether a variable is an ActiveModel or not.
Examples
# bad
user.errors[:name] << 'msg'
user.errors.messages[:name] << 'msg'
# good
user.errors.add(:name, 'msg')
# bad
user.errors[:name].clear
user.errors.messages[:name].clear
# good
user.errors.delete(:name)
# bad
user.errors.keys.include?(:attr)
# good
user.errors.attribute_names.include?(:attr)
Rails/DotSeparatedKeys
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.15 |
- |
Enforces the use of dot-separated locale keys instead of specifying the :scope
option
with an array or a single symbol in I18n
translation methods.
Dot-separated notation is easier to read and trace the hierarchy.
Rails/DuplicateAssociation
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.14 |
2.18 |
Looks for associations that have been defined multiple times in the same file.
When an association is defined multiple times on a model, Active Record overrides the previously defined association with the new one. Because of this, this cop’s autocorrection simply keeps the last of any duplicates and discards the rest.
Rails/DuplicateScope
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.14 |
2.18 |
Checks for multiple scopes in a model that have the same where
clause. This
often means you copy/pasted a scope, updated the name, and forgot to change the condition.
Rails/DurationArithmetic
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.13 |
- |
Checks if a duration is added to or subtracted from Time.current
.
Rails/DynamicFindBy
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Always (Unsafe) |
0.44 |
2.10 |
Checks dynamic find_by_*
methods.
Use find_by
instead of dynamic method.
See. https://rails.rubystyle.guide#find_by
Safety
It is certainly unsafe when not configured properly, i.e. user-defined find_by_xxx
method is not added to cop’s AllowedMethods
.
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)
Configurable attributes
Name | Default value | Configurable values |
---|---|---|
Whitelist |
|
Array |
AllowedMethods |
|
Array |
AllowedReceivers |
|
Array |
Rails/EagerEvaluationLogMessage
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.11 |
- |
Checks that blocks are used for interpolated strings passed to
Rails.logger.debug
.
By default, Rails production environments use the :info
log level.
At the :info
log level, Rails.logger.debug
statements do not result
in log output. However, Ruby must eagerly evaluate interpolated string
arguments passed as method arguments. Passing a block to
Rails.logger.debug
prevents costly evaluation of interpolated strings
when no output would be produced anyway.
Rails/EnumHash
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
2.3 |
- |
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 }
# bad
enum status: [:active, :archived]
# good
enum status: { active: 0, archived: 1 }
Rails/EnumSyntax
Requires Ruby version 3.0 |
Required Rails version: 7.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.26 |
- |
Looks for enums written with keyword arguments syntax.
Defining enums with keyword arguments syntax is deprecated and will be removed in Rails 8.0. Positional arguments should be used instead:
Rails/EnumUniqueness
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.46 |
- |
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]
# 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]
Rails/EnvLocal
Required Rails version: 7.1 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.22 |
- |
Checks for usage of Rails.env.development? || Rails.env.test?
which
can be replaced with Rails.env.local?
, introduced in Rails 7.1.
Rails/EnvironmentComparison
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.52 |
- |
Checks that Rails.env is compared using .production?
-like
methods instead of equality against a string or symbol.
Rails/EnvironmentVariableAccess
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
2.10 |
2.24 |
Looks for direct access to environment variables through the
ENV
variable within the application code. This can lead to runtime
errors due to misconfiguration that could have been discovered at boot
time if the environment variables were loaded as part of initialization
and copied into the application’s configuration or secrets. The cop can
be configured to allow either reads or writes if required.
Rails/Exit
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.41 |
- |
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 ifexit(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.
Rails/ExpandedDateRange
Required Rails version: 5.1 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.11 |
- |
Checks for expanded date range. It only compatible ..
range is targeted.
Incompatible …
range is ignored.
Examples
# bad
date.beginning_of_day..date.end_of_day
date.beginning_of_week..date.end_of_week
date.beginning_of_month..date.end_of_month
date.beginning_of_quarter..date.end_of_quarter
date.beginning_of_year..date.end_of_year
# good
date.all_day
date.all_week
date.all_month
date.all_quarter
date.all_year
Rails/FilePath
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.47 |
2.4 |
Identifies usages of file path joining process to use Rails.root.join
clause.
It is used to add uniformity when joining paths.
Rails/FindBy
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.30 |
2.21 |
Identifies usages of where.take
and change them to use find_by
instead.
And where(…).first
can return different results from find_by
.
(They order records differently, so the "first" record can be different.)
If you also want to detect where.first
, you can set IgnoreWhereFirst
to false.
Rails/FindById
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.7 |
- |
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 | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Always (Unsafe) |
0.30 |
2.21 |
Identifies usages of all.each
and change them to use all.find_each
instead.
Safety
This cop is unsafe if the receiver object is not an Active Record object.
Also, all.each
returns an Array
instance and all.find_each
returns nil,
so the return values are different.
Configurable attributes
Name | Default value | Configurable values |
---|---|---|
AllowedMethods |
|
Array |
AllowedPatterns |
|
Array |
Rails/FreezeTime
Required Rails version: 5.2 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.16 |
- |
Identifies usages of travel_to
with an argument of the current time and
change them to use freeze_time
instead.
Safety
This cop’s autocorrection is unsafe because freeze_time
just delegates to
travel_to
with a default Time.now
, it is not strictly equivalent to Time.now
if the argument of travel_to
is the current time considering time zone.
Examples
# bad
travel_to(Time.now)
travel_to(Time.new)
travel_to(DateTime.now)
travel_to(Time.current)
travel_to(Time.zone.now)
travel_to(Time.now.in_time_zone)
travel_to(Time.current.to_time)
# good
freeze_time
Rails/HasAndBelongsToMany
Rails/HasManyOrHasOneDependent
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.50 |
- |
Looks for has_many
or has_one
associations that don’t
specify a :dependent
option.
It doesn’t register an offense if :through
or dependent: nil
is specified, or if the model is read-only.
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 :articles, dependent: nil
has_many :patients, through: :appointments
end
class User < ActiveRecord::Base
has_many :comments
has_one :avatar
def readonly?
true
end
end
Rails/HelperInstanceVariable
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
2.0 |
- |
Checks for use of the helper methods which reference instance variables.
Relying on instance variables makes it difficult to reuse helper methods.
If it seems awkward to explicitly pass in each dependent variable, consider moving the behavior elsewhere, for example to a model, decorator or presenter.
Provided that a class inherits ActionView::Helpers::FormBuilder
,
an offense will not be registered.
Rails/HttpPositionalArguments
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.44 |
- |
Identifies 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.
It does not detect any cases where include Rack::Test::Methods is used
which makes the http methods incompatible behavior.
|
Rails/HttpStatus
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.54 |
2.11 |
Enforces use of symbolic or numeric value to define HTTP status.
Examples
EnforcedStyle: symbolic (default)
# bad
render :foo, status: 200
render :foo, status: '200'
render json: { foo: 'bar' }, status: 200
render plain: 'foo/bar', status: 304
redirect_to root_url, status: 301
head 200
assert_response 200
assert_redirected_to '/some/path', 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
head :ok
assert_response :ok
assert_redirected_to '/some/path', 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
head :ok
assert_response :ok
assert_redirected_to '/some/path', 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
head 200
assert_response 200
assert_redirected_to '/some/path', status: 301
Rails/I18nLazyLookup
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.14 |
- |
Checks for places where I18n "lazy" lookup can be used.
This cop has two different enforcement modes. When the EnforcedStyle
is lazy
(the default), explicit lookups are added as offenses.
When the EnforcedStyle is explicit
then lazy lookups are added as
offenses.
Examples
EnforcedStyle: lazy (default)
# en.yml
# en:
# books:
# create:
# success: Book created!
# bad
class BooksController < ApplicationController
def create
# ...
redirect_to books_url, notice: t('books.create.success')
end
end
# good
class BooksController < ApplicationController
def create
# ...
redirect_to books_url, notice: t('.success')
end
end
Rails/I18nLocaleAssignment
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.11 |
- |
Checks for the use of I18n.locale=
method.
The locale
attribute persists for the rest of the Ruby runtime, potentially causing
unexpected behavior at a later time.
Using I18n.with_locale
ensures the code passed in the block is the only place I18n.locale
is affected.
It eliminates the possibility of a locale
sticking around longer than intended.
Rails/I18nLocaleTexts
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.14 |
- |
Enforces use of I18n and locale files instead of locale specific strings.
Examples
# bad
class User < ApplicationRecord
validates :email, presence: { message: "must be present" }
end
# good
# config/locales/en.yml
# en:
# activerecord:
# errors:
# models:
# user:
# blank: "must be present"
class User < ApplicationRecord
validates :email, presence: true
end
# bad
class PostsController < ApplicationController
def create
# ...
redirect_to root_path, notice: "Post created!"
end
end
# good
# config/locales/en.yml
# en:
# posts:
# create:
# success: "Post created!"
class PostsController < ApplicationController
def create
# ...
redirect_to root_path, notice: t(".success")
end
end
# bad
class UserMailer < ApplicationMailer
def welcome(user)
mail(to: user.email, subject: "Welcome to My Awesome Site")
end
end
# good
# config/locales/en.yml
# en:
# user_mailer:
# welcome:
# subject: "Welcome to My Awesome Site"
class UserMailer < ApplicationMailer
def welcome(user)
mail(to: user.email)
end
end
Rails/IgnoredColumnsAssignment
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.17 |
- |
Looks for assignments of ignored_columns
that may override previous
assignments.
Overwriting previous assignments is usually a mistake, since it will un-ignore the first set of columns. Since duplicate column names is not a problem, it is better to simply append to the list.
Examples
# bad
class User < ActiveRecord::Base
self.ignored_columns = [:one]
end
# bad
class User < ActiveRecord::Base
self.ignored_columns = [:one, :two]
end
# good
class User < ActiveRecord::Base
self.ignored_columns += [:one, :two]
end
# good
class User < ActiveRecord::Base
self.ignored_columns += [:one]
self.ignored_columns += [:two]
end
Rails/IgnoredSkipActionFilterOption
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.63 |
- |
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
Rails/IndexBy
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
2.5 |
2.8 |
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.
Rails/IndexWith
Required Rails version: 6.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
2.5 |
2.8 |
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.
Rails/Inquiry
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.7 |
- |
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 | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.52 |
- |
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
Rails/LexicallyScopedActionFilter
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
No |
0.52 |
- |
Checks that methods specified in the filter’s only
or
except
options are defined within the same class or module.
Safety
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 behavior 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 behavior 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
Rails/LinkToBlank
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.62 |
- |
Checks for calls to link_to
, link_to_if
, and link_to_unless
methods 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.
Rails/MailerName
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.7 |
- |
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.
Safety
This cop’s autocorrection is unsafe because renaming a constant is always an unsafe operation.
Examples
# bad
class User < ActionMailer::Base
end
class User < ApplicationMailer
end
# good
class UserMailer < ActionMailer::Base
end
class UserMailer < ApplicationMailer
end
Rails/MatchRoute
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.7 |
- |
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
Rails/MigrationClassName
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.14 |
2.20 |
Makes sure that each migration file defines a migration class
whose name matches the file name.
(e.g. 20220224111111_create_users.rb
should define CreateUsers
class.)
Rails/NegateInclude
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.7 |
2.9 |
Enforces the use of collection.exclude?(obj)
over !collection.include?(obj)
.
Safety
This cop is unsafe because false positive will occur for
receiver objects that do not have an exclude?
method. (e.g. IPAddr
)
Rails/NotNullColumn
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.43 |
2.20 |
Checks for add_column calls with a NOT NULL constraint without a default value.
This cop only applies when adding a column to an existing table, since existing records will not have a value for the new column. New tables can freely use NOT NULL columns without defaults, since there are no records that could violate the constraint.
If you need to add a NOT NULL column to an existing table, you must add
it as nullable first, back-fill the data, and then use
change_column_null
. Alternatively, you could add the column with a
default first to have the database automatically backfill existing rows,
and then use change_column_default
to remove the default.
TEXT
cannot have a default value in MySQL.
The cop will automatically detect an adapter from development
environment in config/database.yml
or the environment variable
DATABASE_URL
when the Database
option is not set. If the database
is MySQL, this cop ignores offenses for TEXT
columns.
Examples
# bad
add_column :users, :name, :string, null: false
add_reference :products, :category, null: false
change_table :users do |t|
t.string :name, null: false
end
# good
add_column :users, :name, :string, null: true
add_column :users, :name, :string, null: false, default: ''
change_table :users do |t|
t.string :name, null: false, default: ''
end
add_reference :products, :category
change_column_null :products, :category_id, false
Rails/OrderById
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
2.8 |
- |
Checks for places where ordering by id
column is used.
Don’t use the id
column for ordering. The sequence of ids is not guaranteed
to be in any particular order, despite often (incidentally) being chronological.
Use a timestamp column to order chronologically. As a bonus the intent is clearer.
Make sure the changed order column does not introduce performance bottlenecks and appropriate database indexes are added. |
Examples
# bad
scope :chronological, -> { order(id: :asc) }
scope :chronological, -> { order(primary_key => :asc) }
# good
scope :chronological, -> { order(created_at: :asc) }
Rails/Output
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.15 |
0.19 |
Checks for the use of output calls like puts and print
Safety
This cop’s autocorrection is unsafe because depending on the Rails log level configuration,
changing from puts
to Rails.logger.debug
could result in no output being shown.
Rails/OutputSafety
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.41 |
- |
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><b>hi</b></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><b>hi</b></li><li><b>hi</b></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><b>hi</b>"
# 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<b>hi</b>
# 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
# "<b>hi</b> <span><b>hi</b></span>"
Rails/Pick
Required Rails version: 6.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Always (Unsafe) |
2.6 |
- |
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.
Note that when pick
is added to a relation with an existing limit, it
causes a subquery to be added. In most cases this is undesirable, and
care should be taken while resolving this violation.
Safety
This cop is unsafe because pluck
is defined on both ActiveRecord::Relation
and Enumerable
,
whereas pick
is only defined on ActiveRecord::Relation
in Rails 6.0. This was addressed
in Rails 6.1 via rails/rails#38760, at which point the cop is safe.
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
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.7 |
2.18 |
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.
If the receiver’s relation is not loaded and pluck is used inside an iteration,
it may result in N+1 queries because pluck queries the database on each iteration.
This cop ignores offenses for map/collect when they are suspected to be part of an iteration
to prevent such potential issues.
|
users = User.all
5.times do
users.map { |user| user[:foo] } # Only one query is executed
end
users = User.all
5.times do
users.pluck(:id) # A query is executed on every iteration
end
Safety
This cop is unsafe because model can use column aliases.
# Original code
User.select('name AS nickname').map { |user| user[:nickname] } # => array of nicknames
# After autocorrection
User.select('name AS nickname').pluck(:nickname) # => raises ActiveRecord::StatementInvalid
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 | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
No |
Always (Unsafe) |
2.7 |
- |
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 | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.7 |
2.8 |
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 by running as
a subquery.
This cop has two modes of enforcement. When the EnforcedStyle
is set
to conservative
(the default), only calls to pluck
on a constant
(e.g. a model class) within where
are considered offenses.
Safety
When EnforcedStyle
is set to aggressive
, all calls to pluck
within where
are considered offenses. This might lead to false
positives because the check cannot distinguish between calls to
pluck
on an ActiveRecord::Relation
instance and calls to pluck
on an Array
instance.
Additionally, when using a subquery with the SQL IN
operator,
databases like PostgreSQL and MySQL can’t optimize complex queries as
well. They need to scan all records of the outer table against the
subquery result sequentially, rather than using an index. This can
cause significant performance issues compared to writing the query
differently or using pluck
.
Rails/PluralizationGrammar
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.35 |
- |
Checks for correct grammar when using ActiveSupport’s core extensions to the numeric classes.
Rails/Presence
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.52 |
- |
Checks code that can be written more easily using
Object#presence
defined by Active Support.
Rails/Present
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.48 |
0.67 |
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 enabled. This is
to prevent interference between the autocorrection 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?
Rails/RakeEnvironment
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Always (Unsafe) |
2.4 |
2.6 |
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.
Rails/ReadWriteAttribute
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.20 |
0.29 |
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.
When called from within a method with the same name as the attribute,
read_attribute
and write_attribute
must be used to prevent an
infinite loop:
Examples
# bad
x = read_attribute(:attr)
write_attribute(:attr, val)
# good
x = self[:attr]
self[:attr] = val
# good
def foo
bar || read_attribute(:foo)
end
Rails/RedundantActiveRecordAllMethod
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.21 |
- |
Detect redundant all
used as a receiver for Active Record query methods.
For the methods delete_all
and destroy_all
, this cop will only check cases where the receiver is a model.
It will ignore cases where the receiver is an association (e.g., user.articles.all.delete_all
).
This is because omitting all
from an association changes the methods
from ActiveRecord::Relation
to ActiveRecord::Associations::CollectionProxy
,
which can affect their behavior.
Safety
This cop is unsafe for autocorrection if the receiver for all
is not an Active Record object.
Examples
# bad
User.all.find(id)
User.all.order(:created_at)
users.all.where(id: ids)
user.articles.all.order(:created_at)
# good
User.find(id)
User.order(:created_at)
users.where(id: ids)
user.articles.order(:created_at)
Configurable attributes
Name | Default value | Configurable values |
---|---|---|
AllowedReceivers |
|
Array |
Rails/RedundantAllowNil
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
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
Rails/RedundantForeignKey
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
2.6 |
- |
Detects cases where the :foreign_key
option on associations
is redundant.
Rails/RedundantPresenceValidationOnBelongsTo
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.13 |
- |
Since Rails 5.0 the default for belongs_to
is optional: false
unless config.active_record.belongs_to_required_by_default
is
explicitly set to false
. The presence validator is added
automatically, and explicit presence validation is redundant.
Rails/RedundantReceiverInWithOptions
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.52 |
- |
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/RedundantTravelBack
Required Rails version: 5.2 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.12 |
- |
Checks for redundant travel_back
calls.
Since Rails 5.2, travel_back
is automatically called at the end of the test.
Rails/ReflectionClassName
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Always (Unsafe) |
0.64 |
2.10 |
Checks if the value of the option class_name
, in
the definition of a reflection is a string.
Rails/RefuteMethods
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.56 |
- |
Use assert_not
methods instead of refute
methods.
Rails/RelativeDateConstant
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.48 |
2.13 |
Checks whether constant value isn’t relative date. Because the relative date will be evaluated only once.
Rails/RenderInline
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.7 |
- |
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 | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.7 |
- |
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'
Rails/RequestReferer
Rails/RequireDependency
Required Rails version: 6.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
2.10 |
- |
Checks for the usage of require_dependency
.
require_dependency
is an obsolete method for Rails applications running in Zeitwerk mode.
In Zeitwerk mode, the semantics should match Ruby’s and no need to be defensive with load order,
just refer to classes and modules normally.
If the constant name is dynamic, camelize if needed, and constantize.
Applications running in Zeitwerk mode should not use require_dependency
.
This cop is disabled by default. Please enable it if you are using Zeitwerk mode. |
Rails/ResponseParsedBody
Required Rails version: 5.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.18 |
2.19 |
Prefer response.parsed_body
to custom parsing logic for response.body
.
Safety
This cop is unsafe because Content-Type may not be application/json
or text/html
.
For example, the proprietary Content-Type provided by corporate entities such as
application/vnd.github+json
is not supported at response.parsed_body
by default,
so you still have to use JSON.parse(response.body)
there.
Rails/ReversibleMigration
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.47 |
2.13 |
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
change_table :users do |t|
t.remove :name, type: :string
end
end
# good
def change
create_table :users do |t|
t.string :name
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
# 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
Rails/ReversibleMigrationMethodDefinition
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
2.10 |
2.13 |
Checks whether the migration implements
either a change
method or both an up
and a down
method.
Examples
# bad
class SomeMigration < ActiveRecord::Migration[6.0]
def up
# up migration
end
# <----- missing down method
end
class SomeMigration < ActiveRecord::Migration[6.0]
# <----- missing up method
def down
# down migration
end
end
# good
class SomeMigration < ActiveRecord::Migration[6.0]
def change
# reversible migration
end
end
# good
class SomeMigration < ActiveRecord::Migration[6.0]
def up
# up migration
end
def down
# down migration
end
end
Rails/RootJoinChain
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.13 |
- |
Use a single #join
instead of chaining on Rails.root
or Rails.public_path
.
Examples
# bad
Rails.root.join('db').join('schema.rb')
Rails.root.join('db').join(migrate).join('migration.rb')
Rails.public_path.join('path').join('file.pdf')
Rails.public_path.join('path').join(to).join('file.pdf')
# good
Rails.root.join('db', 'schema.rb')
Rails.root.join('db', migrate, 'migration.rb')
Rails.public_path.join('path', 'file.pdf')
Rails.public_path.join('path', to, 'file.pdf')
Rails/RootPathnameMethods
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.16 |
- |
Use Rails.root
IO methods instead of passing it to File
.
Rails.root
is an instance of Pathname
so we can apply many IO methods directly.
This cop works best when used together with
Style/FileRead
, Style/FileWrite
and Rails/RootJoinChain
.
Safety
This cop is unsafe for autocorrection because Dir
's children
, each_child
, entries
, and glob
methods return string element, but these methods of Pathname
return Pathname
element.
Examples
# bad
File.open(Rails.root.join('db', 'schema.rb'))
File.open(Rails.root.join('db', 'schema.rb'), 'w')
File.read(Rails.root.join('db', 'schema.rb'))
File.binread(Rails.root.join('db', 'schema.rb'))
File.write(Rails.root.join('db', 'schema.rb'), content)
File.binwrite(Rails.root.join('db', 'schema.rb'), content)
Dir.glob(Rails.root.join('db', 'schema.rb'))
Dir[Rails.root.join('db', 'schema.rb')]
# good
Rails.root.join('db', 'schema.rb').open
Rails.root.join('db', 'schema.rb').open('w')
Rails.root.join('db', 'schema.rb').read
Rails.root.join('db', 'schema.rb').binread
Rails.root.join('db', 'schema.rb').write(content)
Rails.root.join('db', 'schema.rb').binwrite(content)
Rails.root.glob("db/schema.rb")
Rails/RootPublicPath
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.15 |
- |
Favor Rails.public_path
over Rails.root
with 'public'
Rails/SafeNavigation
Requires Ruby version 2.3 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.43 |
- |
Converts usages of try!
to &.
. It can also be configured
to convert try
. It will convert code to use safe navigation
if the target Ruby version is set to 2.3+
Rails/SafeNavigationWithBlank
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
2.4 |
- |
Checks to make sure safe navigation isn’t used with blank?
in
a conditional.
Rails/SaveBang
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
Always (Unsafe) |
0.42 |
0.59 |
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 bypersisted?
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: []
Safety
This cop’s autocorrection is unsafe because a custom update
method call would be changed to update!
,
but the method name in the definition would be unchanged.
# Original code
def update_attributes
end
update_attributes
# After running rubocop --safe-autocorrect
def update_attributes
end
update
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: 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 |
|
Boolean |
AllowedReceivers |
|
Array |
Rails/SchemaComment
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
2.13 |
- |
Enforces the use of the comment
option when adding a new table or column
to the database during a migration.
Examples
# bad (no comment for a new column or table)
add_column :table, :column, :integer
create_table :table do |t|
t.type :column
end
# good
add_column :table, :column, :integer, comment: 'Number of offenses'
create_table :table, comment: 'Table of offenses data' do |t|
t.type :column, comment: 'Number of offenses'
end
Rails/ScopeArgs
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.19 |
2.12 |
Checks for scope calls where it was passed a method (usually a scope) instead of a lambda/proc.
Rails/SelectMap
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.21 |
- |
Checks for uses of select(:column_name)
with map(&:column_name)
.
These can be replaced with pluck(:column_name)
.
There also should be some performance improvement since it skips instantiating the model class for matches.
Rails/ShortI18n
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.7 |
- |
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.
Configurable attributes
Name | Default value | Configurable values |
---|---|---|
EnforcedStyle |
|
|
Rails/SkipsModelValidations
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
No |
0.47 |
2.25 |
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 AllowedMethods
.
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')
Configurable attributes
Name | Default value | Configurable values |
---|---|---|
ForbiddenMethods |
|
Array |
AllowedMethods |
|
Array |
Rails/SquishedSQLHeredocs
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.8 |
2.9 |
Checks SQL heredocs to use .squish
.
Safety
Some SQL syntax (e.g. PostgreSQL comments and functions) requires newlines to be preserved in order to work, thus autocorrection for this cop is not safe.
Examples
# bad
<<-SQL
SELECT * FROM posts;
SQL
<<-SQL
SELECT * FROM posts
WHERE id = 1
SQL
execute(<<~SQL, "Post Load")
SELECT * FROM posts
WHERE post_id = 1
SQL
# good
<<-SQL.squish
SELECT * FROM posts;
SQL
<<~SQL.squish
SELECT * FROM table
WHERE id = 1
SQL
execute(<<~SQL.squish, "Post Load")
SELECT * FROM posts
WHERE post_id = 1
SQL
Rails/StripHeredoc
Requires Ruby version 2.3 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.15 |
- |
Enforces the use of squiggly heredoc over strip_heredoc
.
Rails/TableNameAssignment
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
2.14 |
- |
Enforces the absence of explicit table name assignment.
self.table_name=
should only be used for very good reasons,
such as not having control over the database, or working
on a legacy project.
If you need to change how your model’s name is translated to a table name, you may want to look at Inflections: https://api.rubyonrails.org/classes/ActiveSupport/Inflector/Inflections.html
If you wish to add a prefix in front of your model, or wish to change
the default prefix, self.table_name_prefix
might better suit your needs:
https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema.html#method-c-table_name_prefix-3D
STI base classes named Base
are ignored by this cop.
For more information: https://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html
Rails/ThreeStateBooleanColumn
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.19 |
- |
Enforces that boolean columns are created with default values (false
or true
) and
NOT NULL
constraint.
Rails/TimeZone
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.30 |
2.13 |
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
# bad
Time.now
Time.parse('2015-03-02T19:05:37')
'2015-03-02T19:05:37'.to_time
# good
Time.current
Time.zone.now
Time.zone.parse('2015-03-02T19:05:37')
Time.zone.parse('2015-03-02T19:05:37Z') # Respect ISO 8601 format with timezone specifier.
Time.parse('2015-03-02T19:05:37Z') # Also respects ISO 8601
'2015-03-02T19:05:37Z'.to_time # Also respects ISO 8601
Rails/TimeZoneAssignment
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.10 |
- |
Checks for the use of Time.zone=
method.
The zone
attribute persists for the rest of the Ruby runtime, potentially causing
unexpected behavior at a later time.
Using Time.use_zone
ensures the code passed in the block is the only place Time.zone is affected.
It eliminates the possibility of a zone
sticking around longer than intended.
Rails/ToFormattedS
Required Rails version: 7.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.15 |
- |
Checks for consistent uses of to_fs
or to_formatted_s
,
depending on the cop’s configuration.
Configurable attributes
Name | Default value | Configurable values |
---|---|---|
EnforcedStyle |
|
|
Rails/ToSWithArgument
Required Rails version: 7.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Always (Unsafe) |
2.16 |
- |
Identifies passing any argument to #to_s
.
Rails/TopLevelHashWithIndifferentAccess
Required Rails version: 5.1 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.16 |
2.18 |
Identifies top-level HashWithIndifferentAccess
.
This has been soft-deprecated since Rails 5.1.
Rails/TransactionExitStatement
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.14 |
- |
Checks for the use of exit statements (namely return
,
break
and throw
) in transactions. This is due to the eventual
unexpected behavior when using ActiveRecord >= 7, where transactions
exited using these statements are being rollbacked rather than
committed (pre ActiveRecord 7 behavior).
As alternatives, it would be more intuitive to explicitly raise an
error when rollback is desired, and to use next
when commit is
desired.
If you are defining custom transaction methods, you can configure it with TransactionMethods
.
This cop is disabled on Rails >= 7.2 because transactions were restored
to their historical behavior. In Rails 7.1, the behavior is controlled with
the config active_record.commit_transaction_on_non_local_return .
|
Examples
# bad
ApplicationRecord.transaction do
return if user.active?
end
# bad
ApplicationRecord.transaction do
break if user.active?
end
# bad
ApplicationRecord.transaction do
throw if user.active?
end
# bad, as `with_lock` implicitly opens a transaction too
user.with_lock do
throw if user.active?
end
# bad, as `with_lock` implicitly opens a transaction too
ApplicationRecord.with_lock do
break if user.active?
end
# good
ApplicationRecord.transaction do
# Rollback
raise "User is active" if user.active?
end
# good
ApplicationRecord.transaction do
# Commit
next if user.active?
end
Rails/UniqBeforePluck
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always (Unsafe) |
0.40 |
2.13 |
Prefer using distinct
before pluck
instead of uniq
after pluck
.
The use of distinct before pluck is preferred because it executes by 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 uniq
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.
Safety
This cop is unsafe for autocorrection because the behavior may change depending on the database collation.
Examples
EnforcedStyle: conservative (default)
# bad - redundantly fetches duplicate values
Album.pluck(:band_name).uniq
# good
Album.distinct.pluck(:band_name)
EnforcedStyle: aggressive
# bad - redundantly fetches duplicate values
Album.pluck(:band_name).uniq
# bad - redundantly fetches duplicate values
Album.where(year: 1985).pluck(:band_name).uniq
# bad - redundantly fetches duplicate values
customer.favourites.pluck(:color).uniq
# good
Album.distinct.pluck(:band_name)
Album.distinct.where(year: 1985).pluck(:band_name)
customer.favourites.distinct.pluck(:color)
Rails/UniqueValidationWithoutIndex
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
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.
Rails/UnknownEnv
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.51 |
2.18 |
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.
Rails/UnusedIgnoredColumns
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
2.11 |
2.25 |
Suggests you remove a column that does not exist in the schema from ignored_columns
.
ignored_columns
is necessary to drop a column from RDBMS, but you don’t need it after the migration
to drop the column. You avoid forgetting to remove ignored_columns
by this cop.
This cop can’t be used to effectively check for unused columns because the development
and production schema can be out of sync until the migration has been run on production. As such,
this cop can cause ignored_columns to be removed even though the production schema still contains
the column, which can lead to downtime when the migration is actually executed. Only enable this cop
if you know your migrations will be run before any of your Rails applications boot with the modified code.
|
Rails/UnusedRenderContent
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.21 |
- |
If you try to render content along with a non-content status code (100-199, 204, 205, or 304), it will be dropped from the response.
This cop checks for uses of render
which specify both body content and a non-content status.
Rails/Validation
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Always |
0.9 |
0.41 |
Checks for the use of old-style attribute validation macros.
Examples
# bad
validates_acceptance_of :foo
validates_comparison_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, comparison: 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, length: true
validates :foo, uniqueness: true
Rails/WhereEquals
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.9 |
2.26 |
Identifies places where manually constructed SQL
in where
and where.not
can be replaced with
where(attribute: value)
and where.not(attribute: value)
.
Safety
This cop’s autocorrection is unsafe because is may change SQL. See: https://github.com/rubocop/rubocop-rails/issues/403
Examples
# bad
User.where('name = ?', 'Gabe')
User.where.not('name = ?', 'Gabe')
User.where('name = :name', name: 'Gabe')
User.where('name IS NULL')
User.where('name IN (?)', ['john', 'jane'])
User.where('name IN (:names)', names: ['john', 'jane'])
User.where('users.name = :name', name: 'Gabe')
# good
User.where(name: 'Gabe')
User.where.not(name: 'Gabe')
User.where(name: nil)
User.where(name: ['john', 'jane'])
User.where(users: { name: 'Gabe' })
Rails/WhereExists
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.7 |
2.10 |
Enforces consistent style when using exists?
.
Two styles are supported for this cop. When EnforcedStyle is 'exists'
then the cop enforces exists?(…)
over where(…).exists?
.
When EnforcedStyle is 'where' then the cop enforces
where(…).exists?
over exists?(…)
.
Safety
This cop is unsafe for autocorrection because the behavior may change on the following case:
Author.includes(:articles).where(articles: {id: id}).exists?
#=> Perform `eager_load` behavior (`LEFT JOIN` query) and get result.
Author.includes(:articles).exists?(articles: {id: id})
#=> Perform `preload` behavior and `ActiveRecord::StatementInvalid` error occurs.
Examples
EnforcedStyle: exists (default)
# 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)
EnforcedStyle: where
# bad
User.exists?(name: 'john')
User.exists?(['name = ?', 'john'])
user.posts.exists?(published: true)
# good
User.where(name: 'john').exists?
User.where(['name = ?', 'john']).exists?
User.where('name = ?', 'john').exists?
user.posts.where(published: true).exists?
User.where('length(name) > 10').exists?
Rails/WhereMissing
Required Rails version: 6.1 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.16 |
- |
Use where.missing(…)
to find missing relationship records.
This cop is enabled in Rails 6.1 or higher.
Rails/WhereNot
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always |
2.8 |
- |
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 <> ?', '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'])
User.where('users.name != :name', name: 'Gabe')
# good
User.where.not(name: 'Gabe')
User.where.not(name: nil)
User.where.not(name: ['john', 'jane'])
User.where.not(users: { name: 'Gabe' })
Rails/WhereNotWithMultipleConditions
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
2.17 |
2.18 |
Identifies calls to where.not
with multiple hash arguments.
The behavior of where.not
changed in Rails 6.1. Prior to the change,
.where.not(trashed: true, role: 'admin')
evaluated to
WHERE trashed != TRUE AND role != 'admin'
.
From Rails 6.1 onwards, this executes the query
WHERE NOT (trashed == TRUE AND roles == 'admin')
.
Examples
# bad
User.where.not(trashed: true, role: 'admin')
User.where.not(trashed: true, role: ['moderator', 'admin'])
User.joins(:posts).where.not(posts: { trashed: true, title: 'Rails' })
# good
User.where.not(trashed: true)
User.where.not(role: ['moderator', 'admin'])
User.where.not(trashed: true).where.not(role: ['moderator', 'admin'])
User.where.not('trashed = ? OR role = ?', true, 'admin')
Rails/WhereRange
Requires Ruby version 2.6 |
Required Rails version: 6.0 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Always (Unsafe) |
2.25 |
- |
Identifies places where manually constructed SQL
in where
can be replaced with ranges.
Safety
This cop’s autocorrection is unsafe because it can change the query
by explicitly attaching the column to the wrong table.
For example, Booking.joins(:events).where('end_at < ?', Time.current)
will correctly
implicitly attach the end_at
column to the events
table. But when autocorrected to
Booking.joins(:events).where(end_at: …Time.current)
, it will now be incorrectly
explicitly attached to the bookings
table.
Examples
# bad
User.where('age >= ?', 18)
User.where.not('age >= ?', 18)
User.where('age < ?', 18)
User.where('age >= ? AND age < ?', 18, 21)
User.where('age >= :start', start: 18)
User.where('users.age >= ?', 18)
# good
User.where(age: 18..)
User.where.not(age: 18..)
User.where(age: ...18)
User.where(age: 18...21)
User.where(users: { age: 18.. })
# good
# There are no beginless ranges in ruby.
User.where('age > ?', 18)