Rails

Rails/ActionControllerFlashBeforeRender

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.16

-

在 Rails 控制器中使用 flash 赋值在 render 之前会使消息持续时间过长。查看 https://guides.rubyonrails.net.cn/action_controller_overview.html#flash-now

安全

此 cop 的自动更正不安全,因为它用 flash.now 替换了 flash。虽然这通常是一个错误,但它也可能被有意使用。

示例

# bad
class HomeController < ApplicationController
  def create
    flash[:alert] = "msg"
    render :index
  end
end

# good
class HomeController < ApplicationController
  def create
    flash.now[:alert] = "msg"
    render :index
  end
end

Rails/ActionControllerTestCase

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.14

-

不建议使用 ActionController::TestCase,应替换为 ActionDispatch::IntegrationTest。控制器测试过于接近控制器的内部,而集成测试则模拟了浏览器/用户。

安全性

此 cop 的自动更正不安全,因为每个测试用例类的 API 都不相同。在更改超类后,请确保更新控制器测试用例中的每个测试。

示例

# bad
class MyControllerTest < ActionController::TestCase
end

# good
class MyControllerTest < ActionDispatch::IntegrationTest
end

可配置属性

名称 默认值 可配置值

包含

**/test/**/*.rb

数组

Rails/ActionFilter

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

始终

0.19

2.22

强制一致使用动作过滤器方法。

此 cop 可配置,可以强制使用旧的 something_filter 方法或新的 something_action 方法。

此 cop 已弃用。因为 *_filter 方法在 Rails 4.2 中被移除,而该 Rails 版本不再受 RuboCop Rails 支持。此 cop 将在 RuboCop Rails 3.0 中移除。

示例

EnforcedStyle: action(默认)

# bad
after_filter :do_stuff
append_around_filter :do_stuff
skip_after_filter :do_stuff

# good
after_action :do_stuff
append_around_action :do_stuff
skip_after_action :do_stuff

EnforcedStyle: filter

# bad
after_action :do_stuff
append_around_action :do_stuff
skip_after_action :do_stuff

# good
after_filter :do_stuff
append_around_filter :do_stuff
skip_after_filter :do_stuff

可配置属性

名称 默认值 可配置值

EnforcedStyle

action

action, filter

包含

app/controllers/**/*.rb, app/mailers/**/*.rb

数组

Rails/ActionOrder

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.17

-

强制一致排序标准 Rails RESTful 控制器操作。

此 cop 可配置,可以强制执行标准操作的任何排序。所有其他方法都被忽略。因此,在 ExpectedOrder 中指定的动作应在未指定的动作之前定义。

 Rails/ActionOrder:
   ExpectedOrder:
     - index
     - show
     - new
     - edit
     - create
     - update
     - destroy

示例

# bad
def index; end
def destroy; end
def show; end

# good
def index; end
def show; end
def destroy; end

可配置属性

名称 默认值 可配置值

ExpectedOrder

index, show, new, edit, create, update, destroy

数组

包含

app/controllers/**/*.rb

数组

Rails/ActiveRecordAliases

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.53

-

检查是否未使用 ActiveRecord 别名。直接方法名称更清晰,更容易阅读。

安全性

此代码不安全,因为自定义的 `update_attributes` 方法调用已更改为 `update`,但方法定义中的方法名称保持不变。

示例

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

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

Rails/ActiveRecordCallbacksOrder

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.7

-

检查 Active Record 回调是否按执行顺序声明。

示例

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

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

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/ActiveRecordOverride

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.67

2.18

检查是否覆盖了内置的 Active Record 方法,而不是使用回调。

示例

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

# good
class Book < ApplicationRecord
  before_save :upcase_title

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

可配置属性

名称 默认值 可配置值

严重程度

警告

字符串

包含

app/models/**/*.rb

数组

Rails/ActiveSupportAliases

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.48

-

检查是否未使用 ActiveSupport 对核心 Ruby 方法的别名。

示例

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

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

Rails/ActiveSupportOnLoad

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.16

2.24

检查是否直接修补了 Rails 框架类,而不是使用 Active Support 加载钩子。直接修补强制加载引用的框架,使用钩子会延迟加载,直到实际需要。

安全性

虽然建议使用延迟加载钩子,但它会改变代码加载的顺序,并可能暴露加载顺序依赖性错误。

示例

# bad
ActiveRecord::Base.include(MyClass)

# good
ActiveSupport.on_load(:active_record) { include MyClass }

Rails/AddColumnIndex

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.11

2.20

检查使用 `add_column` 的迁移是否具有 `index` 键。`add_column` 不接受 `index`,但也不会对额外的键引发错误,因此可能会错误地添加键,而没有意识到它实际上不会添加索引。

示例

# bad (will not add an index)
add_column :table, :column, :integer, index: true

# good
add_column :table, :column, :integer
add_index :table, :column

可配置属性

名称 默认值 可配置值

包含

db/**/*.rb

数组

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/ApplicationController

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

2.4

2.5

检查控制器是否继承自 ApplicationController

安全性

此规则的自动修正是不安全的,因为它可能会将 ApplicationController 中的逻辑引入到不打算继承其他控制器通用逻辑的控制器中。

示例

# good
class MyController < ApplicationController
  # ...
end

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

Rails/ApplicationJob

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.49

2.5

在 Rails 5.0 中检查作业是否继承自 ApplicationJob

安全性

此规则的自动修正是不安全的,因为它可能会将 ApplicationJob 中的逻辑引入到不打算继承其他作业通用逻辑的作业中。

示例

# good
class Rails5Job < ApplicationJob
  # ...
end

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

Rails/ApplicationMailer

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

2.4

2.5

在 Rails 5.0 中检查邮件器是否继承自 ApplicationMailer

安全性

此规则的自动修正是不安全的,因为它可能会将 ApplicationMailer 中的逻辑引入到不打算继承其他邮件器通用逻辑的邮件器中。

示例

# good
class MyMailer < ApplicationMailer
  # ...
end

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

Rails/ApplicationRecord

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.49

2.5

在 Rails 5.0 中检查模型是否继承自 ApplicationRecord

安全性

此规则的自动修正是不安全的,因为它可能会将 ApplicationRecord 中的逻辑引入到不打算继承其他 Active Record 模型通用逻辑的 Active Record 模型中。

示例

# good
class Rails5Model < ApplicationRecord
  # ...
end

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

Rails/ArelStar

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

2.9

-

防止在 Arel::Table 列引用中使用 "*"

使用 arel_table[""] 会导致输出的字符串成为一个带引号的星号字面量(例如 <tt>`my_model`.</tt>)。这会导致数据库查找名为 <tt>`</tt>(或 `"")的列,而不是像预期的那样扩展列列表。

安全性

此规则的自动修正是不安全的,因为它会将带引号的 转换为 SQL ,不带引号。 是某些 Rails 支持的数据库中有效的列名,即使它通常是一个错误,它也可能表示对名为 的列的合法访问。

示例

# bad
MyTable.arel_table["*"]

# good
MyTable.arel_table[Arel.star]

Rails/AssertNot

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.56

-

使用 assert_not 代替 assert !

示例

# bad
assert !x

# good
assert_not x

可配置属性

名称 默认值 可配置值

包含

**/test/**/*

数组

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

可配置属性

名称 默认值 可配置值

包含

app/models/**/*

数组

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 的自动更正之间发生干扰。

安全

此 cop 的自动更正不安全,因为 ' '.empty? 返回 false,但 ' '.blank? 返回 true。因此,如果接收方是非空空白字符串、制表符或换行符元字符,则自动更正不兼容。

示例

NilOrEmpty: true(默认)

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

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

# good
foo.blank?

NotPresent: true(默认)

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

# bad
!foo.present?

# good
foo.blank?

UnlessPresent: true(默认)

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

# bad
something unless foo.present?

# good
something if foo.blank?

# bad
unless foo.present?
  something
end

# good
if foo.blank?
  something
end

# good
def blank?
  !present?
end

可配置属性

名称 默认值 可配置值

NilOrEmpty

true

布尔值

NotPresent

true

布尔值

UnlessPresent

true

布尔值

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 选项。如果适配器不是 mysql2trilogypostgresqlpostgis,则此 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

可配置属性

名称 默认值 可配置值

Database

<none>

mysql, postgresql

包含

db/**/*.rb

数组

Rails/CompactBlank

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.13

-

检查集合是否可以使用 compact_blank 进行空白压缩。

安全性

默认情况下它是不安全的,因为接收对象块参数的空白检查可能会出现误报。

例如,[[1, 2], [3, nil]].reject { |first, second| second.blank? }[[1, 2], [3, nil]].compact_blank 不兼容。blank? 也是如此。当接收器是哈希对象时,这将正常工作。

并且 compact_blank!ArrayHashActionController::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

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

2.6

2.12

检查 tag 的旧语法用法

当第一个参数是变量时,允许使用 tag,因为 tag(name)tag.public_send(name) 更简单。并且这个 Cop 将在将来被重命名为类似 LegacyTag 的东西。(例如 RuboCop Rails 3.0)

示例

# bad
tag(:p)
tag(:br, class: 'classname')

# good
tag.p
tag.br(class: 'classname')
tag(name, class: 'classname')

可配置属性

名称 默认值 可配置值

Exclude

app/models/**/*.rb, config/**/*.rb

数组

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

可配置属性

名称 默认值 可配置值

包含

db/**/*.rb

数组

Exclude

db/**/*_create_active_storage_tables.active_storage.rb, db/**/*_create_active_storage_variant_records.active_storage.rb

数组

Rails/DangerousColumnNames

默认启用 安全 支持自动更正 添加版本 更改版本

待定

2.21

-

避免使用危险的列名。

某些列名被认为是危险的,因为它们会覆盖已定义的方法。

示例

# bad
add_column :users, :save

# good
add_column :users, :saved

可配置属性

名称 默认值 可配置值

严重程度

警告

字符串

包含

db/**/*.rb

数组

Rails/Date

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.30

2.11

检查 Date 方法的正确使用,例如 Date.today、Date.current 等。

使用 Date.today 是危险的,因为它不知道 Rails 时区。您必须使用 Time.zone.today 代替。

当您使用 to_time 方法时,该代码检查器也会报告警告,因为它也不知道 Rails 时区。

此代码检查器支持两种样式。当 EnforcedStyle 为 'strict' 时,Date 方法 todaycurrentyesterdaytomorrow 被禁止,并且 to_time 和 'to_time_in_current_zone' 的使用被报告为警告。

EnforcedStyleflexible 时,只有 Date.today 被禁止。

您可以使用 AllowToTime: falseto_time 设置警告。AllowToTime 默认值为 true,以防止对 DateTime 对象出现误报。

安全性

此代码检查器的自动更正是不安全的,因为它可能会更改处理时间。

示例

EnforcedStyle: flexible(默认)

# bad
Date.today

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

EnforcedStyle: strict

# bad
Date.current
Date.yesterday
Date.today

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

AllowToTime: true(默认)

# good
date.to_time

AllowToTime: false

# bad
date.to_time

可配置属性

名称 默认值 可配置值

EnforcedStyle

flexible

strictflexible

AllowToTime

true

布尔值

Rails/DefaultScope

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

2.7

-

查找使用 default_scope 的地方。

示例

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

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

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

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

Rails/Delegate

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.21

0.50

查找可以使用 delegate 方法自动创建的委托。

安全导航 &. 被忽略,因为 Rails 的 allow_nil 选项不仅检查 nil,还检查委托是否响应委托方法。

EnforceForPrefixed 选项(默认值为 true)意味着在不使用 delegate 方法的情况下使用目标对象作为方法名称的前缀将被视为违规。当设置为 false 时,这种情况是合法的。

示例

# bad
def bar
  foo.bar
end

# good
delegate :bar, to: :foo

# bad
def bar
  self.bar
end

# good
delegate :bar, to: :self

# good
def bar
  foo&.bar
end

# good
private
def bar
  foo.bar
end

EnforceForPrefixed: true(默认)

# bad
def foo_bar
  foo.bar
end

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

EnforceForPrefixed: false

# good
def foo_bar
  foo.bar
end

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

可配置属性

名称 默认值 可配置值

EnforceForPrefixed

true

布尔值

Rails/DelegateAllowBlank

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.44

-

查找将 :allow_blank 作为选项而不是 :allow_nil 传递的委托。:allow_blank 不是传递给 ActiveSupport#delegate 的有效选项。

示例

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

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

Rails/DeprecatedActiveModelErrorsMethods

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.14

2.18

检查对 ActiveModel#errors 作为哈希的直接操作。这些操作在 Rails 6.1 中已弃用,在 Rails 7 中将不再起作用。

安全性

此 cop 不安全,因为它可能会报告对非 ActiveModel 的 errors 操作,这显然是有效的。cop 无法知道变量是否为 ActiveModel。

示例

# 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

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.15

-

强制使用点分隔的本地化键,而不是在 I18n 翻译方法中使用数组或单个符号指定 :scope 选项。点分隔表示法更易于阅读和跟踪层次结构。

示例

# bad
I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]
I18n.t :title, scope: :invitation

# good
I18n.t 'activerecord.errors.messages.record_invalid'
I18n.t :record_invalid, scope: 'activerecord.errors.messages'

Rails/DuplicateAssociation

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.14

2.18

查找在同一文件中多次定义的关联。

当在模型上多次定义关联时,Active Record 会使用新的关联覆盖先前定义的关联。因此,此 cop 的自动更正只保留任何重复项中的最后一个,并丢弃其余的。

示例

# bad
belongs_to :foo
belongs_to :bar
has_one :foo

# good
belongs_to :bar
has_one :foo

# bad
has_many :foo, class_name: 'Foo'
has_many :bar, class_name: 'Foo'
has_one :baz

# good
has_many :bar, class_name: 'Foo'
has_one :foo

可配置属性

名称 默认值 可配置值

严重程度

警告

字符串

Rails/DuplicateScope

默认启用 安全 支持自动更正 添加版本 更改版本

待定

2.14

2.18

检查模型中具有相同where子句的多个作用域。 这通常意味着您复制/粘贴了一个作用域,更新了名称,但忘记更改条件。

示例

# bad
scope :visible, -> { where(visible: true) }
scope :hidden, -> { where(visible: true) }

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

可配置属性

名称 默认值 可配置值

严重程度

警告

字符串

Rails/DurationArithmetic

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.13

-

检查是否将持续时间添加到或从Time.current中减去。

示例

# bad
Time.current - 1.minute
Time.current + 2.days

# good - using relative would make it harder to express and read
Date.yesterday + 3.days
created_at - 1.minute
3.days - 1.hour

# good
1.minute.ago
2.days.from_now

Rails/DynamicFindBy

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.44

2.10

检查动态find_by_*方法。 使用find_by而不是动态方法。 查看。 https://rails-style-guide.ruby-lang.org.cn#find_by

安全性

当未正确配置时,它肯定是不安全的,即用户定义的find_by_xxx方法未添加到cop的AllowedMethods中。

示例

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

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

AllowedMethods: ['find_by_sql', 'find_by_token_for'] (默认)

# bad
User.find_by_query(users_query)
User.find_by_token_for(:password_reset, token)

# good
User.find_by_sql(users_sql)
User.find_by_token_for(:password_reset, token)

AllowedReceivers: ['Gem::Specification', 'page'] (默认)

# bad
Specification.find_by_name('backend').gem_dir
page.find_by_id('a_dom_id').click

# good
Gem::Specification.find_by_name('backend').gem_dir
page.find_by_id('a_dom_id').click

可配置属性

名称 默认值 可配置值

白名单

find_by_sql, find_by_token_for

数组

AllowedMethods

find_by_sql, find_by_token_for

数组

AllowedReceivers

Gem::Specification, page

数组

Rails/EagerEvaluationLogMessage

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.11

-

检查是否使用块来传递给Rails.logger.debug的插值字符串。

默认情况下,Rails 生产环境使用:info日志级别。 在:info日志级别,Rails.logger.debug语句不会导致日志输出。 但是,Ruby 必须急切地评估作为方法参数传递的插值字符串参数。 将块传递给Rails.logger.debug可以防止在没有任何输出的情况下昂贵地评估插值字符串。

示例

# bad
Rails.logger.debug "The time is #{Time.zone.now}."

# good
Rails.logger.debug { "The time is #{Time.zone.now}." }

Rails/EnumHash

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

2.3

-

查找使用数组语法编写的枚举。

使用数组语法时,在最后一个位置以外的位置添加元素会导致所有先前定义发生偏移。 显式地为每个键指定值可以防止这种情况发生。

示例

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

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

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/EnumUniqueness

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.46

-

查找枚举声明中的重复值。

示例

# 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]

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/EnvLocal

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.22

-

检查 Rails.env.development? || Rails.env.test? 的使用情况,该情况可以用 Rails 7.1 中引入的 Rails.env.local? 替换。

示例

# bad
Rails.env.development? || Rails.env.test?

# good
Rails.env.local?

Rails/EnvironmentComparison

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.52

-

检查 Rails.env 是否使用 .production? 之类的 方法与字符串或符号进行比较。

示例

# bad
Rails.env == 'production'

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

# good
Rails.env.production?

Rails/EnvironmentVariableAccess

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

2.10

2.24

查找应用程序代码中通过 ENV 变量直接访问环境变量的情况。这会导致运行时错误,因为配置错误可能在启动时被发现,如果环境变量作为初始化的一部分加载并复制到应用程序的配置或机密中。该 cop 可以配置为在需要时允许读取或写入。

示例

# good
Rails.application.config.foo
Rails.application.config.x.foo.bar
Rails.application.secrets.foo
Rails.application.config.foo = "bar"

AllowReads: false(默认)

# bad
ENV["FOO"]
ENV.fetch("FOO")

AllowReads: true

# good
ENV["FOO"]
ENV.fetch("FOO")

AllowWrites: false(默认)

# bad
ENV["FOO"] = "bar"

AllowWrites: true

# good
ENV["FOO"] = "bar"

可配置属性

名称 默认值 可配置值

包含

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

数组

Exclude

lib/**/*.rake

数组

AllowReads

false

布尔值

AllowWrites

false

布尔值

Rails/Exit

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.41

-

强制在 Rails 应用程序中不使用 exit 调用。有效的选项是改为引发错误、中断、返回或其他形式的停止当前请求的执行。

有两种明显的情况,exit 在这些情况下特别有害

  • 在应用程序库代码中使用。即使 Rails 会从 SystemExit 中恢复并继续,对该库代码进行单元测试会导致规范退出(如果使用 exit(0),则可能会静默退出)。

  • 在 Web 进程之外的应用程序代码中使用会导致程序退出,这会导致代码无法运行并完成其工作。

示例

# bad
exit(0)

# good
raise 'a bad error has happened'

可配置属性

名称 默认值 可配置值

包含

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

数组

Exclude

lib/**/*.rake

数组

Rails/ExpandedDateRange

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.11

-

检查扩展日期范围。它只兼容 .. 范围。不兼容的 …​ 范围将被忽略。

示例

# 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

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.47

2.4

识别使用文件路径连接过程以使用 Rails.root.join 子句的用法。它用于在连接路径时添加一致性。

示例

EnforcedStyle: 斜杠(默认)

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

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

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

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

EnforcedStyle: 参数

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

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

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

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

可配置属性

名称 默认值 可配置值

EnforcedStyle

斜杠

slashes, arguments

Rails/FindBy

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.30

2.21

识别 where.take 的用法,并将其更改为使用 find_by

where(…​).first 可能返回与 find_by 不同的结果。(它们对记录进行不同的排序,因此“第一个”记录可能不同。)

如果您还想检测 where.first,可以将 IgnoreWhereFirst 设置为 false。

示例

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

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

IgnoreWhereFirst: true(默认)

# good
User.where(name: 'Bruce').first

IgnoreWhereFirst: false

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

可配置属性

名称 默认值 可配置值

IgnoreWhereFirst

true

布尔值

Rails/FindById

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.7

-

强制使用 ActiveRecord#find 而不是 where.take!find_by!find_by_id! 通过主键检索单个记录,前提是您希望找到该记录。

示例

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

# good
User.find(id)

Rails/FindEach

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.30

2.21

识别 all.each 的用法,并将其更改为使用 all.find_each

安全

如果接收器对象不是 Active Record 对象,则此 cop 不安全。此外,all.each 返回 Array 实例,而 all.find_each 返回 nil,因此返回值不同。

示例

# bad
User.all.each

# good
User.all.find_each

AllowedMethods: ['order']

# good
User.order(:foo).each

AllowedPattern: ['order']

# good
User.order(:foo).each

可配置属性

名称 默认值 可配置值

AllowedMethods

order, limit, select, lock

数组

AllowedPatterns

[]

数组

Rails/FreezeTime

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.16

-

识别使用 travel_to 并传入当前时间作为参数的情况,并将其改为使用 freeze_time

安全性

此规则的自动修正不安全,因为 freeze_time 只是使用默认的 Time.now 代理到 travel_to,如果 travel_to 的参数是当前时间,考虑到时区,它并不严格等同于 Time.now

示例

# 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

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.12

-

检查是否使用了 has_and_belongs_to_many 宏。

示例

# bad
# has_and_belongs_to_many :ingredients

# good
# has_many :ingredients, through: :recipe_ingredients

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/HasManyOrHasOneDependent

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.50

-

查找没有指定 :dependent 选项的 has_manyhas_one 关联。

如果指定了 :throughdependent: 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

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/HelperInstanceVariable

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

2.0

-

检查是否使用了引用实例变量的辅助方法。

依赖实例变量会使辅助方法难以重用。

如果显式传递每个依赖变量看起来很笨拙,请考虑将行为移到其他地方,例如模型、装饰器或演示器。

如果一个类继承了 ActionView::Helpers::FormBuilder,则不会注册违规。

示例

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

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

# good
class MyFormBuilder < ActionView::Helpers::FormBuilder
  @template.do_something
end

可配置属性

名称 默认值 可配置值

包含

app/helpers/**/*.rb

数组

Rails/HttpPositionalArguments

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.44

-

识别在测试中使用 getpostputpatch 等 http 方法但不使用关键字参数的情况,并将它们改为使用关键字参数。此规则仅适用于 Rails >= 5。如果您运行的是 Rails < 5,则应禁用 Rails/HttpPositionalArguments 规则或在 .rubocop.yml 文件中将 TargetRailsVersion 设置为 4.2。

它没有检测到任何使用include Rack::Test::Methods的情况,这会导致 HTTP 方法不兼容的行为。

示例

# bad
get :new, { user_id: 1}

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

可配置属性

名称 默认值 可配置值

包含

spec/**/*, test/**/*

数组

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

可配置属性

名称 默认值 可配置值

EnforcedStyle

symbolic

numeric, symbolic

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

EnforcedStyle: explicit

# bad
class BooksController < ApplicationController
  def create
    # ...
    redirect_to books_url, notice: t('.success')
  end
end

# good
class BooksController < ApplicationController
  def create
    # ...
    redirect_to books_url, notice: t('books.create.success')
  end
end

可配置属性

名称 默认值 可配置值

EnforcedStyle

lazy

lazy, explicit

包含

app/controllers/**/*.rb

数组

Rails/I18nLocaleAssignment

默认启用 安全 支持自动更正 添加版本 更改版本

待定

2.11

-

检查使用 I18n.locale= 方法。

locale 属性会持续存在于 Ruby 运行时的剩余部分,可能会在以后导致意外行为。使用 I18n.with_locale 确保传递给块的代码是唯一影响 I18n.locale 的地方。它消除了 locale 持续时间比预期更长的可能性。

示例

# bad
I18n.locale = :fr

# good
I18n.with_locale(:fr) do
end

可配置属性

名称 默认值 可配置值

包含

spec/**/*.rb, test/**/*.rb

数组

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

-

检查ifonly(或except)是否未作为skip_*操作过滤器的选项一起使用。

ifonly一起使用时,if选项将被忽略。类似地,当ifexcept一起使用时,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

可配置属性

名称 默认值 可配置值

包含

app/controllers/**/*.rb, app/mailers/**/*.rb

数组

Rails/IndexBy

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

2.5

2.8

查找将可枚举转换为哈希的each_with_object({}) { …​ }map { …​ }.to_hHash[map { …​ }]的使用,其中值为原始元素。Rails 为此目的提供了index_by方法。

示例

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

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

Rails/IndexWith

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

2.5

2.8

查找将可枚举转换为哈希的each_with_object({}) { …​ }map { …​ }.to_hHash[map { …​ }]的使用,其中键为原始元素。Rails 为此目的提供了index_with方法。

示例

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

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

Rails/Inquiry

默认启用 安全 支持自动更正 添加版本 更改版本

待定

2.7

-

检查是否未使用 Active Support 的inquiry方法。

示例

# 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

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

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

IgnoreScopes: false(默认)

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

IgnoreScopes: true

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

可配置属性

名称 默认值 可配置值

IgnoreScopes

false

布尔值

包含

app/models/**/*.rb

数组

Rails/LexicallyScopedActionFilter

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.52

-

检查过滤器中 onlyexcept 选项中指定的 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

可配置属性

名称 默认值 可配置值

包含

app/controllers/**/*.rb, app/mailers/**/*.rb

数组

Rails/LinkToBlank

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.62

-

检查对 link_to 的调用是否包含 target: '_blank' 但没有 rel: 'noopener'。这可能是一个安全风险,因为加载的页面将控制上一个页面,并可能出于钓鱼目的更改其位置。

选项 rel: 'noreferrer' 也阻止了这种行为,并删除了 http-referrer 头。

示例

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

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

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

Rails/MailerName

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.7

-

强制邮件器名称以 Mailer 后缀结尾。

如果没有 Mailer 后缀,就无法立即清楚地知道什么是邮件器以及哪些视图与邮件器相关。

安全

这个 cop 的自动更正是不安全的,因为重命名常量始终是一个不安全的操作。

示例

# bad
class User < ActionMailer::Base
end

class User < ApplicationMailer
end

# good
class UserMailer < ActionMailer::Base
end

class UserMailer < ApplicationMailer
end

可配置属性

名称 默认值 可配置值

包含

app/mailers/**/*.rb

数组

Rails/MatchRoute

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.7

-

识别使用 match 定义路由可以替换为特定 HTTP 方法的地方。

不要使用 match 定义任何路由,除非需要使用 :via 选项将多个请求类型(在 [:get, :post, :patch, :put, :delete] 中)映射到单个操作。

示例

# 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

可配置属性

名称 默认值 可配置值

包含

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

数组

Rails/MigrationClassName

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.14

2.20

确保每个迁移文件都定义一个迁移类,其名称与文件名匹配。(例如,20220224111111_create_users.rb 应该定义 CreateUsers 类。)

示例

# db/migrate/20220224111111_create_users.rb

# bad
class SellBooks < ActiveRecord::Migration[7.0]
end

# good
class CreateUsers < ActiveRecord::Migration[7.0]
end

可配置属性

名称 默认值 可配置值

包含

db/**/*.rb

数组

Rails/NegateInclude

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.7

2.9

强制使用 collection.exclude?(obj) 而不是 !collection.include?(obj)

安全性

此 cop 不安全,因为对于没有 exclude? 方法的接收器对象,会发生误报。(例如,IPAddr

示例

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

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

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

可配置属性

名称 默认值 可配置值

Database

<none>

mysql

包含

db/**/*.rb

数组

Rails/OrderById

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

2.8

-

检查使用 id 列进行排序的地方。

不要使用 id 列进行排序。尽管 id 的顺序通常(偶然地)是按时间顺序排列的,但不能保证 id 的顺序是按任何特定顺序排列的。使用时间戳列按时间顺序排序。作为奖励,意图更清晰。

确保更改的排序列不会引入性能瓶颈,并添加了适当的数据库索引。

示例

# bad
scope :chronological, -> { order(id: :asc) }
scope :chronological, -> { order(primary_key => :asc) }

# good
scope :chronological, -> { order(created_at: :asc) }

Rails/输出

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.15

0.19

检查是否使用诸如 puts 和 print 之类的输出调用。

安全性

此 cop 的自动更正不安全,因为根据 Rails 日志级别配置,从 puts 更改为 Rails.logger.debug 可能会导致没有输出显示。

示例

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

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

可配置属性

名称 默认值 可配置值

包含

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

数组

Rails/输出安全性

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.41

-

检查是否使用诸如 html_saferawsafe_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>&lt;b&gt;hi&lt;/b&gt;</p>"

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

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

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

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

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

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

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

Rails/Pick

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

2.6

-

强制使用 pick 而不是 pluck(…​).first

使用 pluck 后跟 first 会创建一个中间数组,而 pick 则避免了这种情况。当在 Active Record 关系上调用时,pick 会向查询添加一个限制,以便只从数据库中获取一个值。

请注意,当 pick 被添加到具有现有限制的关系时,它会导致添加一个子查询。在大多数情况下,这是不可取的,在解决此违规时应谨慎行事。

安全性

此 cop 不安全,因为 pluckActiveRecord::RelationEnumerable 上都有定义,而 pick 仅在 Rails 6.0 中的 ActiveRecord::Relation 上定义。这在 Rails 6.1 中通过 rails/rails#38760 得到解决,此时 cop 是安全的。

示例

# 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

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

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

示例

# 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

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

始终(不安全)

2.7

-

强制使用 ids 而不是 pluck(:id)pluck(primary_key)

安全性

如果接收对象不是 Active Record 对象,则此 cop 不安全。

示例

# 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

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.7

2.8

识别在 where 查询方法中使用 pluck 的地方,并可以使用 select 替换。

由于 pluck 是一个急切方法,会立即访问数据库,因此使用 select 有助于避免额外的数据库查询。

此 cop 有两种不同的执行模式。当 EnforcedStyleconservative(默认值)时,仅将 where 中对常量(即模型类)的 pluck 调用用作违规。

安全性

EnforcedStyleaggressive 时,where 中对 pluck 的所有调用都用作违规。这可能会导致误报,因为 cop 无法在对 ActiveRecord::Relation 实例的 pluck 调用与对 Array 实例的 pluck 调用之间替换为 select

示例

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

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

EnforcedStyle:conservative(默认值)

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

EnforcedStyle:aggressive

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

可配置属性

名称 默认值 可配置值

EnforcedStyle

conservative

conservative, aggressive

Rails/PluralizationGrammar

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.35

-

检查使用 ActiveSupport 对数字类进行核心扩展时是否使用正确的语法。

示例

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

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

Rails/Presence

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.52

-

检查可以使用 Active Support 定义的 Object#presence 更轻松地编写的代码。

示例

# bad
a.present? ? a : nil

# bad
!a.present? ? nil : a

# bad
a.blank? ? nil : a

# bad
!a.blank? ? a : nil

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

# bad
!a.present? ? b : a

# bad
a.blank? ? b : a

# bad
!a.blank? ? a : b

# good
a.presence || b

Rails/Present

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.48

0.67

检查可以使用 Active Support 定义的 Object#present? 更简单的条件编写代码。

Style/UnlessElse 的交互:如果启用了 Style/UnlessElse,则 NotBlank 的配置在 unless else 上下文中不会产生违规。这是为了防止两个 cop 的自动更正之间的干扰。

示例

NotNilAndNotEmpty:true(默认)

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

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

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

# good
foo.present?

NotBlank:true(默认)

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

# bad
!foo.blank?

# bad
not foo.blank?

# good
foo.present?

UnlessBlank:true(默认)

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

# bad
something unless foo.blank?

# good
something if foo.present?

可配置属性

名称 默认值 可配置值

NotNilAndNotEmpty

true

布尔值

NotBlank

true

布尔值

UnlessBlank

true

布尔值

Rails/RakeEnvironment

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

2.4

2.6

检查没有 :environment 任务依赖项的 Rake 任务。:environment 任务为其他 Rake 任务加载应用程序代码。没有它,任务就无法使用模型等应用程序代码。

如果任务满足以下条件之一,您可以忽略违规

  • 任务不需要应用程序代码。

  • 任务调用 :environment 任务。

安全

在大多数情况下可能不是问题,但调用 :environment 任务可能会破坏行为。它也更慢。例如,某些只需要加载一个 gem 才能运行的任务,在不加载整个应用程序的情况下运行速度会快得多。

示例

# bad
task :foo do
  do_something
end

# good
task foo: :environment do
  do_something
end

可配置属性

名称 默认值 可配置值

包含

**/Rakefile**/*.rake

数组

Exclude

lib/capistrano/tasks/**/*.rake

数组

Rails/ReadWriteAttribute

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.20

0.29

检查使用 read_attributewrite_attribute 方法,并建议使用方括号代替。

如果实例中缺少属性(例如,由部分 select 初始化),则 read_attribute 将返回 nil,但方括号将引发 ActiveModel::MissingAttributeError

在这种情况下显式引发错误是更好的选择,这就是 rubocop 建议使用方括号的原因。

当从与属性同名的方法内部调用时,必须使用 read_attributewrite_attribute 来防止无限循环

示例

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

# good
x = self[:attr]
self[:attr] = val
# good
def foo
  bar || read_attribute(:foo)
end

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/RedundantActiveRecordAllMethod

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.21

-

检测用作 Active Record 查询方法接收者的冗余 all

对于 delete_alldestroy_all 方法,此 cop 将仅检查接收者是模型的情况。它将忽略接收者是关联的情况(例如,user.articles.all.delete_all)。这是因为从关联中省略 all 会将方法从 ActiveRecord::Relation 更改为 ActiveRecord::Associations::CollectionProxy,这会影响它们的行为。

安全

如果 all 的接收者不是 Active Record 对象,则此 cop 对自动更正不安全。

示例

# 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)

允许的接收者:['ActionMailer::Preview', 'ActiveSupport::TimeZone'](默认)

# good
ActionMailer::Preview.all.first
ActiveSupport::TimeZone.all.first

可配置属性

名称 默认值 可配置值

AllowedReceivers

ActionMailer::PreviewActiveSupport::TimeZone

数组

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

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/RedundantForeignKey

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

2.6

-

检测关联中 :foreign_key 选项是否冗余的情况。

示例

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

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

# good
class Post
  has_many :comments
end

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

Rails/RedundantPresenceValidationOnBelongsTo

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.13

-

从 Rails 5.0 开始,belongs_to 的默认值为 optional: false,除非显式将 config.active_record.belongs_to_required_by_default 设置为 false。存在验证器会自动添加,显式存在验证是冗余的。

安全

此 cop 的自动更正不安全,因为它将默认错误消息从“不能为空”更改为“必须存在”。

示例

# bad
belongs_to :user
validates :user, presence: true

# bad
belongs_to :user
validates :user_id, presence: true

# bad
belongs_to :author, foreign_key: :user_id
validates :user_id, presence: true

# good
belongs_to :user

# good
belongs_to :author, foreign_key: :user_id

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

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.12

-

检查是否存在冗余的 travel_back 调用。从 Rails 5.2 开始,travel_back 会在测试结束时自动调用。

示例

# bad
def teardown
  do_something
  travel_back
end

# good
def teardown
  do_something
end

# bad
after do
  do_something
  travel_back
end

# good
after do
  do_something
end

可配置属性

名称 默认值 可配置值

包含

spec/**/*.rb, test/**/*.rb

数组

Rails/ReflectionClassName

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.64

2.10

检查反射定义中选项 class_name 的值是否为字符串。

安全

此 cop 不安全,因为它无法确定指定给 class_name 的常量或方法返回值是否为字符串。

示例

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

# good
has_many :accounts, class_name: 'Account'

Rails/RefuteMethods

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.56

-

使用 assert_not 方法代替 refute 方法。

示例

强制风格:assert_not(默认)

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

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

强制风格:refute

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

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

可配置属性

名称 默认值 可配置值

EnforcedStyle

assert_not

assert_not, refute

包含

**/test/**/*

数组

Rails/RelativeDateConstant

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.48

2.13

检查常量值是否不是相对日期。因为相对日期只会被评估一次。

安全性

此 cop 的自动更正是不安全的,因为它对常量的依赖没有被更正。

示例

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

# good
class SomeClass
  EXPIRES = 1.week

  def self.expired_at
    EXPIRES.since
  end
end

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

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: 的地方。

示例

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

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

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

ContentTypeCompatibility:true(默认)

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

ContentTypeCompatibility:false

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

可配置属性

名称 默认值 可配置值

ContentTypeCompatibility

true

布尔值

Rails/RequestReferer

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.41

-

检查 request.refererrequest.referrer 的一致使用,具体取决于 cop 的配置。

示例

强制风格:referer(默认)

# bad
request.referrer

# good
request.referer

强制风格:referrer

# bad
request.referer

# good
request.referrer

可配置属性

名称 默认值 可配置值

EnforcedStyle

referer

referer, referrer

Rails/RequireDependency

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

2.10

-

检查 require_dependency 的使用情况。

require_dependency 是在 Zeitwerk 模式下运行的 Rails 应用程序的过时方法。在 Zeitwerk 模式下,语义应该与 Ruby 的一致,不需要对加载顺序进行防御,只需正常引用类和模块即可。如果常量名称是动态的,则根据需要进行驼峰式转换,并进行常量化。

在 Zeitwerk 模式下运行的应用程序不应使用 require_dependency

此 cop 默认情况下处于禁用状态。如果您使用 Zeitwerk 模式,请启用它。

示例

# bad
require_dependency 'some_lib'

Rails/ResponseParsedBody

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.18

2.19

优先使用 response.parsed_body 而不是为 response.body 自定义解析逻辑。

安全性

此 cop 不安全,因为 Content-Type 可能不是 application/jsontext/html。例如,企业实体(如 application/vnd.github+json)提供的专有 Content-Type 默认情况下不受 response.parsed_body 支持,因此您仍然需要在那里使用 JSON.parse(response.body)

示例

# bad
JSON.parse(response.body)

# bad
Nokogiri::HTML.parse(response.body)

# bad
Nokogiri::HTML5.parse(response.body)

# good
response.parsed_body

可配置属性

名称 默认值 可配置值

包含

spec/controllers/**/*.rb, spec/requests/**/*.rb, test/controllers/**/*.rb, test/integration/**/*.rb

数组

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

可配置属性

名称 默认值 可配置值

包含

db/**/*.rb

数组

Rails/ReversibleMigrationMethodDefinition

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

2.10

2.13

检查迁移是否实现了 change 方法或同时实现了 updown 方法。

示例

# 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

可配置属性

名称 默认值 可配置值

包含

db/**/*.rb

数组

Rails/RootJoinChain

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.13

-

使用单个 #join 而不是在 Rails.rootRails.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.rootPathname 的实例,因此我们可以直接应用许多 IO 方法。

此 cop 与 Style/FileReadStyle/FileWriteRails/RootJoinChain 一起使用时效果最佳。

安全性

此 cop 对自动更正不安全,因为 Dirchildreneach_childentriesglob 方法返回字符串元素,但 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/RootPublicPath

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.15

-

优先使用 Rails.public_path 而不是 Rails.root 加上 'public'

示例

# bad
Rails.root.join('public')
Rails.root.join('public/file.pdf')
Rails.root.join('public', 'file.pdf')

# good
Rails.public_path
Rails.public_path.join('file.pdf')
Rails.public_path.join('file.pdf')

Rails/SafeNavigation

所需的 Ruby 版本:2.3
默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.43

-

try! 的用法转换为 &.。它也可以配置为转换 try。如果目标 Ruby 版本设置为 2.3+,它将转换代码以使用安全导航。

示例

ConvertTry: false(默认)

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

foo.try!(:[], 0)

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

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

ConvertTry: true

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

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

可配置属性

名称 默认值 可配置值

ConvertTry

false

布尔值

Rails/SafeNavigationWithBlank

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

2.4

-

检查以确保安全导航没有在条件语句中与 blank? 一起使用。

安全

虽然安全导航运算符通常是一个好主意,但在条件语句中检查 foo&.blank? 时,foonil 实际上会与作者的意图相反。

例如

foo&.blank? #=> nil
foo.blank? #=> true

示例

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

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

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: true (默认)

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

def save_user
  user.save
end

AllowImplicitReturn: false

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

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

def save_user
  user.save!
end

def save_user
  return user.save
end

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

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

module Service::Mailer
  self.create
end

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

可配置属性

名称 默认值 可配置值

AllowImplicitReturn

true

布尔值

AllowedReceivers

[]

数组

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/ScopeArgs

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.19

2.12

检查范围调用,其中传递了方法(通常是范围)而不是 lambda/proc。

示例

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

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

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/SelectMap

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.21

-

检查使用select(:column_name)map(&:column_name)的情况。这些可以用pluck(:column_name)替换。

由于它跳过了对匹配项实例化模型类,因此还应该有一些性能改进。

安全

此 cop 不安全,因为模型可能会覆盖属性 getter。此外,使用pluck时会跳过模型的after_initialize钩子。

示例

# bad
Model.select(:column_name).map(&:column_name)

# good
Model.pluck(:column_name)

Rails/ShortI18n

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.7

-

强制使用I18n方法的简短形式:t而不是translatel而不是localize

此 cop 有两种不同的执行模式。当 EnforcedStyle 为 conservative(默认)时,仅将I18n.translateI18n.localize调用添加为违规。

当 EnforcedStyle 为 aggressive 时,所有没有接收者的translatelocalize调用都将被添加为违规。

示例

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

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

EnforcedStyle: conservative (默认)

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

EnforcedStyle: aggressive

# bad
translate :key
localize Time.now

# good
t :key
l Time.now

可配置属性

名称 默认值 可配置值

EnforcedStyle

conservative

conservative, aggressive

Rails/SkipsModelValidations

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.47

2.7

可以通过配置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')

AllowedMethods: ["touch"]

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

# good
user.touch

可配置属性

名称 默认值 可配置值

ForbiddenMethods

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

数组

AllowedMethods

[]

数组

Rails/SquishedSQLHeredocs

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.8

2.9

检查 SQL heredocs 以使用 .squish

安全性

某些 SQL 语法(例如 PostgreSQL 注释和函数)需要保留换行符才能正常工作,因此此 cop 的自动更正不安全。

示例

# 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

所需的 Ruby 版本:2.3
默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.15

-

强制使用波浪号 heredoc 而不是 strip_heredoc

示例

# bad
<<EOS.strip_heredoc
  some text
EOS

# bad
<<-EOS.strip_heredoc
  some text
EOS

# good
<<~EOS
  some text
EOS

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

示例

# bad
self.table_name = 'some_table_name'
self.table_name = :some_other_name

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/ThreeStateBooleanColumn

默认启用 安全 支持自动更正 添加版本 更改版本

待定

2.19

-

强制布尔值列创建时使用默认值(falsetrue)以及 NOT NULL 约束。

示例

# bad
add_column :users, :active, :boolean
t.column :active, :boolean
t.boolean :active

# good
add_column :users, :active, :boolean, default: true, null: false
t.column :active, :boolean, default: true, null: false
t.boolean :active, default: true, null: false

可配置属性

名称 默认值 可配置值

包含

db/**/*.rb

数组

Rails/TimeZone

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.30

2.13

检查是否使用没有时区的 Time 方法。

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

EnforcedStyle: flexible(默认)

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

# good
Time.at(timestamp).in_time_zone

EnforcedStyle: strict

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

# bad
Time.at(timestamp).in_time_zone

可配置属性

名称 默认值 可配置值

EnforcedStyle

flexible

strictflexible

Exclude

**/*.gemspec

数组

Rails/TimeZoneAssignment

默认启用 安全 支持自动更正 添加版本 更改版本

待定

2.10

-

检查是否使用 Time.zone= 方法。

zone 属性会持续存在于 Ruby 运行时的剩余部分,可能会在以后导致意外行为。使用 Time.use_zone 确保代码块中传递的代码是唯一影响 Time.zone 的地方。它消除了 zone 持续存在时间过长的可能性。

示例

# bad
Time.zone = 'EST'

# good
Time.use_zone('EST') do
end

可配置属性

名称 默认值 可配置值

包含

spec/**/*.rb, test/**/*.rb

数组

Rails/ToFormattedS

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.15

-

检查是否一致地使用 to_fsto_formatted_s,具体取决于 cop 的配置。

示例

EnforcedStyle: to_fs(默认)

# bad
time.to_formatted_s(:db)

# good
time.to_fs(:db)

EnforcedStyle: to_formatted_s

# bad
time.to_fs(:db)

# good
time.to_formatted_s(:db)

可配置属性

名称 默认值 可配置值

EnforcedStyle

to_fs

to_fs, to_formatted_s

Rails/ToSWithArgument

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

2.16

-

识别向 #to_s 传递任何参数的情况。

安全性

此 cop 被标记为不安全,因为它可能会检测到与 Active Support 实现无关的 #to_s 调用。

示例

# bad
obj.to_s(:delimited)

# good
obj.to_formatted_s(:delimited)

Rails/TopLevelHashWithIndifferentAccess

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.16

2.18

识别顶层 HashWithIndifferentAccess。自 Rails 5.1 以来,此功能已软弃用。

示例

# bad
HashWithIndifferentAccess.new(foo: 'bar')

# good
ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar')

可配置属性

名称 默认值 可配置值

严重程度

警告

字符串

Rails/TransactionExitStatement

默认启用 安全 支持自动更正 添加版本 更改版本

待定

2.14

-

检查事务中是否使用退出语句(即 returnbreakthrow)。这是因为在使用 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

TransactionMethods: ["custom_transaction"]

# bad
CustomModel.custom_transaction do
  return if user.active?
end

可配置属性

名称 默认值 可配置值

TransactionMethods

[]

数组

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 调用。

安全性

此 cop 对自动更正不安全,因为行为可能会根据数据库排序规则而改变。

示例

强制风格:保守(默认)

# 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)

可配置属性

名称 默认值 可配置值

EnforcedStyle

conservative

conservative, aggressive

Rails/UniqueValidationWithoutIndex

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

2.5

-

当你在 Active Record 模型中定义唯一性验证时,你应该为该列添加一个唯一索引。有两个原因。首先,即使定义了 Active Record 的验证,也可能出现重复记录。其次,这会导致查询速度变慢。验证在插入/更新记录时会执行一个包含目标列的 SELECT 语句。如果该列没有索引且表很大,则查询会很重。

请注意,如果 db/schema.rb 不存在,则该 cop 不会执行任何操作。

示例

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

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

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

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/UnknownEnv

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.51

2.18

检查使用 Rails.env 谓词调用的环境是否存在。默认情况下,该 cop 允许 Rails 附带的三个环境:developmenttestproduction。更多环境可以添加到 Environments 配置参数中。

示例

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

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

可配置属性

名称 默认值 可配置值

严重程度

警告

字符串

环境

developmenttestproduction

数组

Rails/UnusedIgnoredColumns

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

2.11

2.25

建议您从 ignored_columns 中删除在模式中不存在的列。ignored_columns 是从 RDBMS 中删除列所必需的,但在删除列后的迁移中不再需要。通过此 cop,您可以避免忘记删除 ignored_columns

此 cop 不能有效地检查未使用的列,因为开发和生产模式可能不同步,直到迁移在生产环境中运行。因此,此 cop 可能会导致 ignored_columns 被删除,即使生产模式仍然包含该列,这会导致迁移实际执行时出现停机。只有在您知道迁移将在任何 Rails 应用程序使用修改后的代码启动之前运行时,才启用此 cop。

示例

# bad
class User < ApplicationRecord
  self.ignored_columns = [:already_removed_column]
end

# good
class User < ApplicationRecord
  self.ignored_columns = [:still_existing_column]
end

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

Rails/UnusedRenderContent

默认启用 安全 支持自动更正 添加版本 更改版本

待定

2.21

-

如果您尝试在非内容状态代码(100-199、204、205 或 304)中渲染内容,则该内容将从响应中删除。

此 cop 检查 render 的使用情况,这些使用情况同时指定了正文内容和非内容状态。

示例

# bad
render 'foo', status: :continue
render status: 100, plain: 'Ruby!'

# good
head :continue
head 100

可配置属性

名称 默认值 可配置值

严重程度

警告

字符串

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

可配置属性

名称 默认值 可配置值

包含

app/models/**/*.rb

数组

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?

可配置属性

名称 默认值 可配置值

EnforcedStyle

exists

existswhere

Rails/WhereMissing

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

2.16

-

使用 where.missing(…​) 查找缺少的关系记录。

此 cop 在 Rails 6.1 或更高版本中启用。

示例

# bad
Post.left_joins(:author).where(authors: { id: nil })

# good
Post.where.missing(:author)

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)