Rails
Rails/ActionControllerFlashBeforeRender
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终(不安全) |
2.16 |
- |
在 Rails 控制器中使用 flash
赋值在 render
之前会使消息持续时间过长。查看 https://guides.rubyonrails.net.cn/action_controller_overview.html#flash-now
Rails/ActionControllerTestCase
Rails/ActionFilter
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已禁用 |
是 |
始终 |
0.19 |
2.22 |
强制一致使用动作过滤器方法。
此 cop 可配置,可以强制使用旧的 something_filter 方法或新的 something_action 方法。
此 cop 已弃用。因为 *_filter 方法在 Rails 4.2 中被移除,而该 Rails 版本不再受 RuboCop Rails 支持。此 cop 将在 RuboCop Rails 3.0 中移除。
|
Rails/ActionOrder
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.17 |
- |
强制一致排序标准 Rails RESTful 控制器操作。
此 cop 可配置,可以强制执行标准操作的任何排序。所有其他方法都被忽略。因此,在 ExpectedOrder
中指定的动作应在未指定的动作之前定义。
Rails/ActionOrder:
ExpectedOrder:
- index
- show
- new
- edit
- create
- update
- destroy
Rails/ActiveRecordCallbacksOrder
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.7 |
- |
检查 Active Record 回调是否按执行顺序声明。
Rails/ActiveRecordOverride
Rails/ActiveSupportAliases
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.48 |
- |
检查是否未使用 ActiveSupport 对核心 Ruby 方法的别名。
Rails/ActiveSupportOnLoad
Rails/AddColumnIndex
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.11 |
2.20 |
检查使用 `add_column` 的迁移是否具有 `index` 键。`add_column` 不接受 `index`,但也不会对额外的键引发错误,因此可能会错误地添加键,而没有意识到它实际上不会添加索引。
Rails/AfterCommitOverride
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
否 |
2.8 |
- |
强制每个模型只有一个对 `after_commit`(及其别名 - `after_create_commit`、`after_update_commit` 和 `after_destroy_commit`)的调用,并且具有相同的回调名称。
示例
# 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/ApplicationRecord
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终(不安全) |
0.49 |
2.5 |
在 Rails 5.0 中检查模型是否继承自 ApplicationRecord
。
Rails/ArelStar
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终(不安全) |
2.9 |
- |
防止在 Arel::Table 列引用中使用 "*"
。
使用 arel_table[""]
会导致输出的字符串成为一个带引号的星号字面量(例如 <tt>`my_model`.</tt>)。这会导致数据库查找名为 <tt>`
</tt>(或 `"
"
)的列,而不是像预期的那样扩展列列表。
Rails/AttributeDefaultBlockValue
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.9 |
- |
查找 attribute
类方法,这些方法指定 :default
选项,其值为数组、字符串字面量或不带块的方法调用。它将接受所有其他值,例如字符串、符号、整数和浮点数字面量以及常量。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.62 |
- |
查找 belongs_to 关联,其中我们通过弃用的 required
选项控制关联是否为必需。
从 Rails 5 开始,belongs_to 关联默认情况下是必需的,这可以通过使用 optional: true
来控制。
来自发行说明
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)
如果开发人员正在使用 required: false
,我们肯定希望自动更正为 optional: true
。
但是,在不知道他们是否已覆盖 config.active_record.belongs_to_required_by_default
的默认值的情况下,我们无法确定是否可以安全地删除 required: true
或者是否应该将其替换为 optional: false
(或者类似地,删除多余的 optional: false
)。因此,在我们使用 required: true
的情况下,我们将简单地将其反转为 optional: false
,用户可以根据其默认值进行删除。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终(不安全) |
0.48 |
2.10 |
检查可以使用 Active Support 定义的 Object#blank?
更简单的条件编写的代码。
与 Style/UnlessElse
的交互:如果启用了 Style/UnlessElse
,则 NotPresent
的配置在 unless else
上下文中不会产生违规。这是为了防止两个 cop 的自动更正之间发生干扰。
Rails/BulkChangeTable
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.57 |
2.20 |
检查 ALTER 查询是否可以组合。如果检测到可组合的查询,它会建议您使用 change_table
并设置 bulk: true
。此选项会导致迁移生成一个将多个列更改组合在一起的 ALTER TABLE 语句。
bulk
选项仅在 MySQL 和 PostgreSQL(5.2 及更高版本)适配器上受支持;因此,它会自动从 development
环境中的 config/database.yml
或环境变量 DATABASE_URL
中检测适配器,前提是未设置 Database
选项。如果适配器不是 mysql2
、trilogy
、postgresql
或 postgis
,则此 Cop 会忽略违规。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
否 |
始终(不安全) |
2.13 |
- |
检查集合是否可以使用 compact_blank
进行空白压缩。
安全性
默认情况下它是不安全的,因为接收对象块参数的空白检查可能会出现误报。
例如,[[1, 2], [3, nil]].reject { |first, second| second.blank? }
和 [[1, 2], [3, nil]].compact_blank
不兼容。blank?
也是如此。当接收器是哈希对象时,这将正常工作。
并且 compact_blank!
对 Array
、Hash
和 ActionController::Parameters
具有不同的实现。Array#compact_blank!
、Hash#compact_blank!
等效于 delete_if(&:blank?)
。ActionController::Parameters#compact_blank!
等效于 reject!(&:blank?)
。如果 Cop 犯了错误,自动更正的代码可能会出现意外行为。
示例
# bad
collection.reject(&:blank?)
collection.reject { |_k, v| v.blank? }
# 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.reject!(&:blank?) # Same behavior as `ActionController::Parameters#compact_blank!`
collection.reject! { |_k, v| v.blank? } # Same behavior as `ActionController::Parameters#compact_blank!`
# good
collection.compact_blank!
Rails/ContentTag
Rails/CreateTableWithTimestamps
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.52 |
2.20 |
检查迁移是否在创建新表时未包含时间戳。在许多情况下,时间戳是有用的信息,应该添加。
允许在 id: false 时不写 timestamps ,因为这强调了尊重用户的编辑意图。
|
示例
# 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/Date
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终(不安全) |
0.30 |
2.11 |
检查 Date 方法的正确使用,例如 Date.today、Date.current 等。
使用 Date.today
是危险的,因为它不知道 Rails 时区。您必须使用 Time.zone.today
代替。
当您使用 to_time
方法时,该代码检查器也会报告警告,因为它也不知道 Rails 时区。
此代码检查器支持两种样式。当 EnforcedStyle
为 'strict' 时,Date 方法 today
、current
、yesterday
和 tomorrow
被禁止,并且 to_time
和 'to_time_in_current_zone' 的使用被报告为警告。
当 EnforcedStyle
为 flexible
时,只有 Date.today
被禁止。
您可以使用 AllowToTime: false
为 to_time
设置警告。AllowToTime
默认值为 true
,以防止对 DateTime
对象出现误报。
Rails/Delegate
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.21 |
0.50 |
查找可以使用 delegate
方法自动创建的委托。
安全导航 &.
被忽略,因为 Rails 的 allow_nil
选项不仅检查 nil,还检查委托是否响应委托方法。
EnforceForPrefixed
选项(默认值为 true
)意味着在不使用 delegate
方法的情况下使用目标对象作为方法名称的前缀将被视为违规。当设置为 false
时,这种情况是合法的。
Rails/DeprecatedActiveModelErrorsMethods
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
否 |
始终(不安全) |
2.14 |
2.18 |
检查对 ActiveModel#errors 作为哈希的直接操作。这些操作在 Rails 6.1 中已弃用,在 Rails 7 中将不再起作用。
Rails/DotSeparatedKeys
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.15 |
- |
强制使用点分隔的本地化键,而不是在 I18n
翻译方法中使用数组或单个符号指定 :scope
选项。点分隔表示法更易于阅读和跟踪层次结构。
Rails/DuplicateAssociation
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.14 |
2.18 |
查找在同一文件中多次定义的关联。
当在模型上多次定义关联时,Active Record 会使用新的关联覆盖先前定义的关联。因此,此 cop 的自动更正只保留任何重复项中的最后一个,并丢弃其余的。
Rails/DuplicateScope
Rails/DurationArithmetic
Rails/DynamicFindBy
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
否 |
始终(不安全) |
0.44 |
2.10 |
检查动态find_by_*
方法。 使用find_by
而不是动态方法。 查看。 https://rails-style-guide.ruby-lang.org.cn#find_by
示例
# 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)
Rails/EagerEvaluationLogMessage
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.11 |
- |
检查是否使用块来传递给Rails.logger.debug
的插值字符串。
默认情况下,Rails 生产环境使用:info
日志级别。 在:info
日志级别,Rails.logger.debug
语句不会导致日志输出。 但是,Ruby 必须急切地评估作为方法参数传递的插值字符串参数。 将块传递给Rails.logger.debug
可以防止在没有任何输出的情况下昂贵地评估插值字符串。
Rails/EnumHash
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
2.3 |
- |
查找使用数组语法编写的枚举。
使用数组语法时,在最后一个位置以外的位置添加元素会导致所有先前定义发生偏移。 显式地为每个键指定值可以防止这种情况发生。
Rails/EnvironmentVariableAccess
Rails/Exit
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.41 |
- |
强制在 Rails 应用程序中不使用 exit
调用。有效的选项是改为引发错误、中断、返回或其他形式的停止当前请求的执行。
有两种明显的情况,exit
在这些情况下特别有害
-
在应用程序库代码中使用。即使 Rails 会从
SystemExit
中恢复并继续,对该库代码进行单元测试会导致规范退出(如果使用exit(0)
,则可能会静默退出)。 -
在 Web 进程之外的应用程序代码中使用会导致程序退出,这会导致代码无法运行并完成其工作。
Rails/ExpandedDateRange
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.11 |
- |
检查扩展日期范围。它只兼容 ..
范围。不兼容的 …
范围将被忽略。
Rails/FilePath
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.47 |
2.4 |
识别使用文件路径连接过程以使用 Rails.root.join
子句的用法。它用于在连接路径时添加一致性。
Rails/FindBy
Rails/FindById
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.7 |
- |
强制使用 ActiveRecord#find
而不是 where.take!
、find_by!
和 find_by_id!
通过主键检索单个记录,前提是您希望找到该记录。
Rails/FindEach
Rails/FreezeTime
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终(不安全) |
2.16 |
- |
识别使用 travel_to
并传入当前时间作为参数的情况,并将其改为使用 freeze_time
。
安全性
此规则的自动修正不安全,因为 freeze_time
只是使用默认的 Time.now
代理到 travel_to
,如果 travel_to
的参数是当前时间,考虑到时区,它并不严格等同于 Time.now
。
Rails/HasAndBelongsToMany
Rails/HasManyOrHasOneDependent
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.50 |
- |
查找没有指定 :dependent
选项的 has_many
或 has_one
关联。
如果指定了 :through
或 dependent: nil
,或者模型是只读的,则不会注册违规。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
2.0 |
- |
检查是否使用了引用实例变量的辅助方法。
依赖实例变量会使辅助方法难以重用。
如果显式传递每个依赖变量看起来很笨拙,请考虑将行为移到其他地方,例如模型、装饰器或演示器。
如果一个类继承了 ActionView::Helpers::FormBuilder
,则不会注册违规。
Rails/HttpPositionalArguments
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.44 |
- |
识别在测试中使用 get
、post
、put
、patch
等 http 方法但不使用关键字参数的情况,并将它们改为使用关键字参数。此规则仅适用于 Rails >= 5。如果您运行的是 Rails < 5,则应禁用 Rails/HttpPositionalArguments 规则或在 .rubocop.yml 文件中将 TargetRailsVersion 设置为 4.2。
它没有检测到任何使用include Rack::Test::Methods 的情况,这会导致 HTTP 方法不兼容的行为。
|
Rails/HttpStatus
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.54 |
2.11 |
强制使用符号或数值来定义 HTTP 状态。
示例
EnforcedStyle: symbolic(默认)
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.14 |
- |
检查 I18n "lazy" 查找可以使用的位置。
这个 cop 有两种不同的执行模式。当 EnforcedStyle 为 lazy
(默认)时,显式查找将被添加为违规。
当 EnforcedStyle 为 explicit
时,lazy 查找将被添加为违规。
示例
EnforcedStyle: lazy(默认)
# 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/I18nLocaleTexts
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
否 |
2.14 |
- |
强制使用 I18n 和 locale 文件而不是特定于 locale 的字符串。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终(不安全) |
2.17 |
- |
查找可能覆盖先前分配的ignored_columns
分配。
覆盖先前分配通常是一个错误,因为它将取消忽略第一组列。由于重复的列名不是问题,因此最好简单地追加到列表中。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.63 |
- |
检查if
和only
(或except
)是否未作为skip_*
操作过滤器的选项一起使用。
当if
和only
一起使用时,if
选项将被忽略。类似地,当if
和except
一起使用时,except
选项将被忽略。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
2.5 |
2.8 |
查找将可枚举转换为哈希的each_with_object({}) { … }
、map { … }.to_h
和Hash[map { … }]
的使用,其中值为原始元素。Rails 为此目的提供了index_by
方法。
Rails/IndexWith
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
2.5 |
2.8 |
查找将可枚举转换为哈希的each_with_object({}) { … }
、map { … }.to_h
和Hash[map { … }]
的使用,其中键为原始元素。Rails 为此目的提供了index_with
方法。
Rails/Inquiry
Rails/InverseOf
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.52 |
- |
查找 has_(one|many) 和 belongs_to 关联,其中 Active Record 由于范围或使用的选项而无法自动确定反向关联。使用下面的带有 order 范围的博客示例,使用blog.posts.first.blog
双向遍历博客的关联会导致blog
从数据库中加载两次。
必须手动指定:inverse_of
才能让 Active Record 使用内存中的关联对象,或者设置为false
以选择退出。请注意,设置nil
不会阻止 Active Record 自动尝试确定反向关联,并且不被视为此处的有效值。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
否 |
否 |
0.52 |
- |
检查过滤器中 only
或 except
选项中指定的 method 是否在同一个类或模块中定义。
安全
从技术上讲,你可以指定超类的 method 或 mixin 添加的 method 到过滤器中,但这可能会让开发者感到困惑。如果你指定了在其他类或模块中定义的 method,你应该在该类或模块中定义过滤器。
如果你依赖超类操作中定义的行为,你必须记住在子类操作中调用 super
。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.62 |
- |
检查对 link_to
的调用是否包含 target: '_blank'
但没有 rel: 'noopener'
。这可能是一个安全风险,因为加载的页面将控制上一个页面,并可能出于钓鱼目的更改其位置。
选项 rel: 'noreferrer'
也阻止了这种行为,并删除了 http-referrer 头。
Rails/MailerName
Rails/MatchRoute
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.7 |
- |
识别使用 match
定义路由可以替换为特定 HTTP 方法的地方。
不要使用 match
定义任何路由,除非需要使用 :via
选项将多个请求类型(在 [:get, :post, :patch, :put, :delete] 中)映射到单个操作。
Rails/MigrationClassName
Rails/NegateInclude
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
否 |
始终(不安全) |
2.7 |
2.9 |
强制使用 collection.exclude?(obj)
而不是 !collection.include?(obj)
。
Rails/NotNullColumn
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.43 |
2.20 |
检查带有 NOT NULL 约束但没有默认值的 add_column 调用。
此 cop 仅在向现有表添加列时适用,因为现有记录将没有新列的值。新表可以自由使用没有默认值的 NOT NULL 列,因为没有记录会违反约束。
如果您需要向现有表添加 NOT NULL 列,则必须先将其添加为可空,回填数据,然后使用 change_column_null
。或者,您可以先使用默认值添加列,让数据库自动回填现有行,然后使用 change_column_default
删除默认值。
TEXT
在 MySQL 中不能有默认值。当未设置 Database
选项时,cop 会自动从 config/database.yml
中的 development
环境或环境变量 DATABASE_URL
中检测适配器。如果数据库是 MySQL,此 cop 会忽略 TEXT
列的违规。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已禁用 |
是 |
否 |
2.8 |
- |
检查使用 id
列进行排序的地方。
不要使用 id
列进行排序。尽管 id 的顺序通常(偶然地)是按时间顺序排列的,但不能保证 id 的顺序是按任何特定顺序排列的。使用时间戳列按时间顺序排序。作为奖励,意图更清晰。
确保更改的排序列不会引入性能瓶颈,并添加了适当的数据库索引。 |
Rails/输出
Rails/输出安全性
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.41 |
- |
检查是否使用诸如 html_safe
、raw
和 safe_concat
之类的输出安全调用。这些方法不会转义内容。它们只是返回包含内容原样的 SafeBuffer。相反,请使用 safe_join
来连接内容并转义它,以及使用 concat 来连接内容并转义它,以确保其安全性。
示例
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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
否 |
始终(不安全) |
2.6 |
- |
强制使用 pick
而不是 pluck(…).first
。
使用 pluck
后跟 first
会创建一个中间数组,而 pick
则避免了这种情况。当在 Active Record 关系上调用时,pick
会向查询添加一个限制,以便只从数据库中获取一个值。
请注意,当 pick
被添加到具有现有限制的关系时,它会导致添加一个子查询。在大多数情况下,这是不可取的,在解决此违规时应谨慎行事。
安全性
此 cop 不安全,因为 pluck
在 ActiveRecord::Relation
和 Enumerable
上都有定义,而 pick
仅在 Rails 6.0 中的 ActiveRecord::Relation
上定义。这在 Rails 6.1 中通过 rails/rails#38760 得到解决,此时 cop 是安全的。
Rails/Pluck
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
否 |
始终(不安全) |
2.7 |
2.18 |
强制使用 pluck
而不是 map
。
pluck
可用于代替 map
从可枚举的每个元素中提取单个键。当在 Active Record 关系上调用时,它会生成一个更有效的查询,该查询只选择必要的键。
安全性
此 cop 不安全,因为模型可以使用列别名。
# 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
Rails/PluckId
Rails/PluckInWhere
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
否 |
始终(不安全) |
2.7 |
2.8 |
识别在 where
查询方法中使用 pluck
的地方,并可以使用 select
替换。
由于 pluck
是一个急切方法,会立即访问数据库,因此使用 select
有助于避免额外的数据库查询。
此 cop 有两种不同的执行模式。当 EnforcedStyle
为 conservative
(默认值)时,仅将 where
中对常量(即模型类)的 pluck
调用用作违规。
安全性
当 EnforcedStyle
为 aggressive
时,where
中对 pluck
的所有调用都用作违规。这可能会导致误报,因为 cop 无法在对 ActiveRecord::Relation
实例的 pluck
调用与对 Array
实例的 pluck
调用之间替换为 select
。
Rails/Presence
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.52 |
- |
检查可以使用 Active Support 定义的 Object#presence
更轻松地编写的代码。
Rails/Present
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.48 |
0.67 |
检查可以使用 Active Support 定义的 Object#present?
更简单的条件编写代码。
与 Style/UnlessElse
的交互:如果启用了 Style/UnlessElse
,则 NotBlank
的配置在 unless else
上下文中不会产生违规。这是为了防止两个 cop 的自动更正之间的干扰。
Rails/RakeEnvironment
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
否 |
始终(不安全) |
2.4 |
2.6 |
检查没有 :environment
任务依赖项的 Rake 任务。:environment
任务为其他 Rake 任务加载应用程序代码。没有它,任务就无法使用模型等应用程序代码。
如果任务满足以下条件之一,您可以忽略违规
-
任务不需要应用程序代码。
-
任务调用
:environment
任务。
Rails/ReadWriteAttribute
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.20 |
0.29 |
检查使用 read_attribute
或 write_attribute
方法,并建议使用方括号代替。
如果实例中缺少属性(例如,由部分 select
初始化),则 read_attribute
将返回 nil,但方括号将引发 ActiveModel::MissingAttributeError
。
在这种情况下显式引发错误是更好的选择,这就是 rubocop 建议使用方括号的原因。
当从与属性同名的方法内部调用时,必须使用 read_attribute
和 write_attribute
来防止无限循环
Rails/RedundantActiveRecordAllMethod
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
否 |
始终(不安全) |
2.21 |
- |
检测用作 Active Record 查询方法接收者的冗余 all
。
对于 delete_all
和 destroy_all
方法,此 cop 将仅检查接收者是模型的情况。它将忽略接收者是关联的情况(例如,user.articles.all.delete_all
)。这是因为从关联中省略 all
会将方法从 ActiveRecord::Relation
更改为 ActiveRecord::Associations::CollectionProxy
,这会影响它们的行为。
Rails/RedundantAllowNil
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.67 |
- |
检查 Rails 模型验证中是否存在冗余的 allow_nil
,当 allow_blank
存在时。
示例
# 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/RedundantPresenceValidationOnBelongsTo
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终(不安全) |
2.13 |
- |
从 Rails 5.0 开始,belongs_to
的默认值为 optional: false
,除非显式将 config.active_record.belongs_to_required_by_default
设置为 false
。存在验证器会自动添加,显式存在验证是冗余的。
Rails/RedundantReceiverInWithOptions
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.52 |
- |
检查 with_options
中是否存在冗余的接收者。从 Rails 4.2 或更高版本开始,接收者是隐式的。
示例
# 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
Rails/RefuteMethods
Rails/RelativeDateConstant
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终(不安全) |
0.48 |
2.13 |
检查常量值是否不是相对日期。因为相对日期只会被评估一次。
Rails/RenderInline
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
否 |
2.7 |
- |
查找控制器操作中的内联渲染。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.7 |
- |
识别可以使用 render plain:
替换 render text:
的地方。
Rails/RequireDependency
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已禁用 |
是 |
否 |
2.10 |
- |
检查 require_dependency
的使用情况。
require_dependency
是在 Zeitwerk 模式下运行的 Rails 应用程序的过时方法。在 Zeitwerk 模式下,语义应该与 Ruby 的一致,不需要对加载顺序进行防御,只需正常引用类和模块即可。如果常量名称是动态的,则根据需要进行驼峰式转换,并进行常量化。
在 Zeitwerk 模式下运行的应用程序不应使用 require_dependency
。
此 cop 默认情况下处于禁用状态。如果您使用 Zeitwerk 模式,请启用它。 |
Rails/ResponseParsedBody
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
否 |
始终(不安全) |
2.18 |
2.19 |
优先使用 response.parsed_body
而不是为 response.body
自定义解析逻辑。
安全性
此 cop 不安全,因为 Content-Type 可能不是 application/json
或 text/html
。例如,企业实体(如 application/vnd.github+json
)提供的专有 Content-Type 默认情况下不受 response.parsed_body
支持,因此您仍然需要在那里使用 JSON.parse(response.body)
。
Rails/ReversibleMigration
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.47 |
2.13 |
检查迁移文件中的 change 方法是否可逆。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已禁用 |
是 |
否 |
2.10 |
2.13 |
检查迁移是否实现了 change
方法或同时实现了 up
和 down
方法。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.13 |
- |
使用单个 #join
而不是在 Rails.root
或 Rails.public_path
上进行链接。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终(不安全) |
2.16 |
- |
使用 Rails.root
IO 方法,而不是将其传递给 File
。
Rails.root
是 Pathname
的实例,因此我们可以直接应用许多 IO 方法。
此 cop 与 Style/FileRead
、Style/FileWrite
和 Rails/RootJoinChain
一起使用时效果最佳。
安全性
此 cop 对自动更正不安全,因为 Dir
的 children
、each_child
、entries
和 glob
方法返回字符串元素,但 Pathname
的这些方法返回 Pathname
元素。
示例
# 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)
# 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/SafeNavigation
所需的 Ruby 版本:2.3 |
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.43 |
- |
将 try!
的用法转换为 &.
。它也可以配置为转换 try
。如果目标 Ruby 版本设置为 2.3+,它将转换代码以使用安全导航。
Rails/SafeNavigationWithBlank
Rails/SaveBang
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已禁用 |
是 |
始终(不安全) |
0.42 |
0.59 |
识别可能的情况下,应该使用 Active Record save! 或相关方法而不是 save,因为模型可能保存失败,而异常比未处理的失败更好。
这将允许
-
更新或保存调用,分配给变量,或用作 if/unless/case 语句中的条件。
-
创建调用,分配给变量,该变量随后调用
persisted?
,或其返回值立即由persisted?
检查。 -
如果结果显式地从方法和代码块中返回,或作为参数提供,则调用。
-
签名看起来不像 ActiveRecord 持久化方法的调用。
默认情况下,它还将允许从方法和代码块中隐式返回。这种行为可以通过 AllowImplicitReturn: false
关闭。
您可以使用 AllowedReceivers: []
允许产生误报的接收器。
安全
此 cop 的自动更正不安全,因为自定义 update
方法调用将更改为 update!
,但定义中的方法名称将保持不变。
# Original code
def update_attributes
end
update_attributes
# After running rubocop --safe-autocorrect
def update_attributes
end
update
示例
# 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
Rails/SchemaComment
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已禁用 |
是 |
否 |
2.13 |
- |
在迁移过程中添加新表或列到数据库时,强制使用comment
选项。
示例
# 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/SelectMap
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
否 |
始终(不安全) |
2.21 |
- |
检查使用select(:column_name)
和map(&:column_name)
的情况。这些可以用pluck(:column_name)
替换。
由于它跳过了对匹配项实例化模型类,因此还应该有一些性能改进。
Rails/ShortI18n
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.7 |
- |
强制使用I18n
方法的简短形式:t
而不是translate
,l
而不是localize
。
此 cop 有两种不同的执行模式。当 EnforcedStyle 为 conservative(默认)时,仅将I18n.translate
和I18n.localize
调用添加为违规。
当 EnforcedStyle 为 aggressive 时,所有没有接收者的translate
和localize
调用都将被添加为违规。
Rails/SkipsModelValidations
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
0.47 |
2.7 |
检查使用跳过验证的方法,这些方法列在https://guides.rubyonrails.net.cn/active_record_validations.html#skipping-validations
可以通过配置AllowedMethods
来忽略此规则中的方法。
示例
# 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')
Rails/SquishedSQLHeredocs
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终(不安全) |
2.8 |
2.9 |
检查 SQL heredocs 以使用 .squish
。
示例
# 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
Rails/TableNameAssignment
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已禁用 |
是 |
否 |
2.14 |
- |
强制禁止显式表名赋值。
self.table_name=
应该只在有充分理由的情况下使用,例如无法控制数据库或处理遗留项目。
如果您需要更改模型名称如何转换为表名,您可能需要查看 Inflections: https://api.rubyonrails.net.cn/classes/ActiveSupport/Inflector/Inflections.html
如果您希望在模型前面添加前缀,或希望更改默认前缀,self.table_name_prefix
可能更适合您的需求: https://api.rubyonrails.net.cn/classes/ActiveRecord/ModelSchema.html#method-c-table_name_prefix-3D
命名为 Base
的 STI 基类会被此 cop 忽略。更多信息: https://api.rubyonrails.net.cn/classes/ActiveRecord/Inheritance.html
Rails/ThreeStateBooleanColumn
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
否 |
2.19 |
- |
强制布尔值列创建时使用默认值(false
或 true
)以及 NOT NULL
约束。
Rails/TimeZone
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终(不安全) |
0.30 |
2.13 |
检查是否使用没有时区的 Time 方法。
基于 Ruby on Rails 风格指南 (https://rails-style-guide.ruby-lang.org.cn#time) 和文章 http://danilenko.org/2012/7/6/rails_timezones/
此 cop 支持两种风格。当 EnforcedStyle
为 'strict' 时,只允许使用 Time.zone
。
当 EnforcedStyle 为 'flexible' 时,也允许使用 Time#in_time_zone
。
示例
# 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.
Rails/TimeZoneAssignment
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
否 |
2.10 |
- |
检查是否使用 Time.zone=
方法。
zone
属性会持续存在于 Ruby 运行时的剩余部分,可能会在以后导致意外行为。使用 Time.use_zone
确保代码块中传递的代码是唯一影响 Time.zone 的地方。它消除了 zone
持续存在时间过长的可能性。
Rails/ToFormattedS
Rails/TopLevelHashWithIndifferentAccess
Rails/TransactionExitStatement
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
否 |
2.14 |
- |
检查事务中是否使用退出语句(即 return
、break
和 throw
)。这是因为在使用 ActiveRecord >= 7 时,最终会发生意外行为,其中使用这些语句退出的事务将被回滚而不是提交(ActiveRecord 7 之前的行为)。
作为替代方案,当需要回滚时,更直观的是显式地引发错误,而当需要提交时,则使用 next
。
如果您正在定义自定义事务方法,则可以使用 TransactionMethods
进行配置。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终(不安全) |
0.40 |
2.13 |
建议在 pluck
之前使用 distinct
,而不是在 pluck
之后使用 uniq
。
在 pluck 之前使用 distinct 是首选的,因为它由数据库执行。
此 cop 有两种不同的执行模式。当 EnforcedStyle 为 conservative
(默认值)时,只有在 uniq
之前对常量(即模型类)调用 pluck
时,才会将其添加为违规。
当 EnforcedStyle 为 aggressive
时,所有在 distinct 之前调用 pluck
的情况都会被添加为违规。这可能会导致误报,因为 cop 无法区分对 ActiveRecord::Relation 的 pluck
调用与对 ActiveRecord::Associations::CollectionProxy 的 pluck
调用。
示例
强制风格:保守(默认)
# bad - redundantly fetches duplicate values
Album.pluck(:band_name).uniq
# good
Album.distinct.pluck(:band_name)
强制风格:激进
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
否 |
2.5 |
- |
当你在 Active Record 模型中定义唯一性验证时,你应该为该列添加一个唯一索引。有两个原因。首先,即使定义了 Active Record 的验证,也可能出现重复记录。其次,这会导致查询速度变慢。验证在插入/更新记录时会执行一个包含目标列的 SELECT
语句。如果该列没有索引且表很大,则查询会很重。
请注意,如果 db/schema.rb 不存在,则该 cop 不会执行任何操作。
Rails/UnknownEnv
Rails/UnusedIgnoredColumns
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已禁用 |
是 |
否 |
2.11 |
2.25 |
建议您从 ignored_columns
中删除在模式中不存在的列。ignored_columns
是从 RDBMS 中删除列所必需的,但在删除列后的迁移中不再需要。通过此 cop,您可以避免忘记删除 ignored_columns
。
此 cop 不能有效地检查未使用的列,因为开发和生产模式可能不同步,直到迁移在生产环境中运行。因此,此 cop 可能会导致 ignored_columns 被删除,即使生产模式仍然包含该列,这会导致迁移实际执行时出现停机。只有在您知道迁移将在任何 Rails 应用程序使用修改后的代码启动之前运行时,才启用此 cop。
|
Rails/Validation
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
已启用 |
是 |
始终 |
0.9 |
0.41 |
检查旧式属性验证宏的使用。
示例
# 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, length: true
validates :foo, uniqueness: true
Rails/WhereEquals
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终(不安全) |
2.9 |
2.10 |
识别在 where
中手动构建的 SQL 可以用 where(attribute: value)
替换的地方。
安全性
此 cop 的自动更正不安全,因为它可能会更改 SQL。请参阅:https://github.com/rubocop/rubocop-rails/issues/403
示例
# bad
User.where('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(name: nil)
User.where(name: ['john', 'jane'])
User.where(users: { name: 'Gabe' })
Rails/WhereExists
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终(不安全) |
2.7 |
2.10 |
在使用 exists?
时强制执行一致的样式。
此 cop 支持两种样式。当 EnforcedStyle 为 'exists' 时,cop 强制执行 exists?(…)
而不是 where(…).exists?
。
当 EnforcedStyle 为 'where' 时,cop 强制执行 where(…).exists?
而不是 exists?(…)
。
安全性
此 cop 对自动更正不安全,因为在以下情况下行为可能会改变
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.
示例
EnforcedStyle: exists(默认)
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.16 |
- |
使用 where.missing(…)
查找缺少的关系记录。
此 cop 在 Rails 6.1 或更高版本中启用。
Rails/WhereNot
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.8 |
- |
识别可以在 where
中用 where.not(…)
替换手动构建的 SQL 的地方。
示例
# 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
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
否 |
2.17 |
2.18 |
识别对 where.not
的调用,其中包含多个哈希参数。
where.not
的行为在 Rails 6.1 中发生了改变。在更改之前,.where.not(trashed: true, role: 'admin')
评估为 WHERE trashed != TRUE AND role != 'admin'
。从 Rails 6.1 开始,这将执行查询 WHERE NOT (trashed == TRUE AND roles == 'admin')
。
示例
# 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
所需的 Ruby 版本:2.6 |
默认启用 | 安全 | 支持自动更正 | 添加版本 | 更改版本 |
---|---|---|---|---|
待定 |
是 |
始终 |
2.25 |
- |
识别可以在 where
中用范围替换手动构建的 SQL 的地方。
示例
# 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)