Class: RuboCop::Cop::DevDoc::Rails::EnumMustBeSymbolized
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::DevDoc::Rails::EnumMustBeSymbolized
- Defined in:
- lib/rubocop/cop/dev_doc/rails/enum_must_be_symbolized.rb
Overview
Every Rails ‘enum` declaration must be paired with `enum_symbolize` so the reader returns a symbol instead of Rails’ default string form.
## Rationale Strings and symbols are not equal in Ruby (‘:foo == ’foo’‘ is `false`). Rails’ ‘enum` macro defines a reader that returns the string form, so downstream comparisons like `record.status == :active` silently fail. Pairing `enum :status, …` with `enum_symbolize :status` overrides the reader to hand back a symbol, eliminating the footgun.
See ‘best_practices/backend/en/01a_defensive_programming.md` item 7.
❌
class Reimbursement < ApplicationRecord
enum :payment_status, { draft: 0, pending: 1, finalized: 2 }
end
✔
class Reimbursement < ApplicationRecord
enum :payment_status, { draft: 0, pending: 1, finalized: 2 }
enum_symbolize :payment_status
end
‘enum_symbolize` accepts multiple names so several enums can be paired in one call:
✔
enum_symbolize :payment_status, :finalize_intent
Constant Summary collapse
- MSG =
'Pair `enum :%<name>s` with `enum_symbolize :%<name>s` so the reader returns a symbol ' \ '(see backend/01a_defensive_programming.md item 7).'.freeze
Instance Method Summary collapse
Instance Method Details
#on_class(node) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/rubocop/cop/dev_doc/rails/enum_must_be_symbolized.rb', line 54 def on_class(node) body = node.body return unless body statements = body.begin_type? ? body.children : [body] enum_decls = [] symbolized = [] statements.each do |stmt| next unless stmt.respond_to?(:send_type?) && stmt.send_type? if (name = enum_call(stmt)) enum_decls << [name, stmt] elsif (args = enum_symbolize_call(stmt)) symbolized.concat(args.select(&:sym_type?).map(&:value)) end end enum_decls.each do |name, decl| next if symbolized.include?(name) add_offense(decl, message: format(MSG, name: name)) end end |