Rails 7.1+
After this pull request you don't need some hacks. If you want the enum value to be validated before saving, use the option :validate
:
class Conversation < ApplicationRecord
enum :status, %i[active archived], validate: true
end
conversation = Conversation.new
conversation.status = :unknown
conversation.valid? # => false
conversation.status = nil
conversation.valid? # => false
conversation.status = :active
conversation.valid? # => true
It is also possible to pass additional validation options:
class Conversation < ApplicationRecord
enum :status, %i[active archived], validate: { allow_nil: true }
end
conversation = Conversation.new
conversation.status = :unknown
conversation.valid? # => false
conversation.status = nil
conversation.valid? # => true
conversation.status = :active
conversation.valid? # => true
If not pass this option (or explicitly pass validate: nil
or validate: false
), validation doesn't invoke and ArgumentError
raises in case of invalid value
Before Rails 7.1
Rails automatically validate this value raising error
def assert_valid_value(value)
unless value.blank? || mapping.has_key?(value) || mapping.has_value?(value)
raise ArgumentError, "'#{value}' is not a valid #{name}"
end
end
What you can is override this method with empty body
# config/initializers/enum_prevent_argument_error.rb
module ActiveRecord
module Enum
class EnumType < Type::Value
def assert_valid_value(_)
end
end
end
end
After that validation validates :status, inclusion: { in: statuses.keys }
will work (without this monkey patch ArgumentError
raises). Warning: If you apply this monkey patch, you should double check that all enums have this validation. If there is no validation and no check constraint, invalid values will be saved as is in the database and will be as nil
attriubute in the AR model