diff options
Diffstat (limited to 'activerecord/lib/active_record/enum.rb')
-rw-r--r-- | activerecord/lib/active_record/enum.rb | 79 |
1 files changed, 39 insertions, 40 deletions
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index c0d9d9c1c8..8fba6fcc35 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -18,10 +18,9 @@ module ActiveRecord # conversation.archived? # => true # conversation.status # => "archived" # - # # conversation.update! status: 1 + # # conversation.status = 1 # conversation.status = "archived" # - # # conversation.update! status: nil # conversation.status = nil # conversation.status.nil? # => true # conversation.status # => nil @@ -47,13 +46,13 @@ module ActiveRecord # Good practice is to let the first declared status be the default. # # Finally, it's also possible to explicitly map the relation between attribute and - # database integer with a +Hash+: + # database integer with a hash: # # class Conversation < ActiveRecord::Base # enum status: { active: 0, archived: 1 } # end # - # Note that when an +Array+ is used, the implicit mapping from the values to database + # Note that when an array is used, the implicit mapping from the values to database # integers is derived from the order the values appear in the array. In the example, # <tt>:active</tt> is mapped to +0+ as it's the first element, and <tt>:archived</tt> # is mapped to +1+. In general, the +i+-th element is mapped to <tt>i-1</tt> in the @@ -61,7 +60,7 @@ module ActiveRecord # # Therefore, once a value is added to the enum array, its position in the array must # be maintained, and new values should only be added to the end of the array. To - # remove unused values, the explicit +Hash+ syntax should be used. + # remove unused values, the explicit hash syntax should be used. # # In rare circumstances you might need to access the mapping directly. # The mappings are exposed through a class method with the pluralized attribute @@ -75,22 +74,24 @@ module ActiveRecord # # Conversation.where("status <> ?", Conversation.statuses[:archived]) # - # You can use the +:enum_prefix+ or +:enum_suffix+ options when you need - # to define multiple enums with same values. If the passed value is +true+, - # the methods are prefixed/suffixed with the name of the enum. + # You can use the +:_prefix+ or +:_suffix+ options when you need to define + # multiple enums with same values. If the passed value is +true+, the methods + # are prefixed/suffixed with the name of the enum. It is also possible to + # supply a custom value: # - # class Invoice < ActiveRecord::Base - # enum verification: [:done, :fail], enum_prefix: true + # class Conversation < ActiveRecord::Base + # enum status: [:active, :archived], _suffix: true + # enum comments_status: [:active, :inactive], _prefix: :comments # end # - # It is also possible to supply a custom prefix. + # With the above example, the bang and predicate methods along with the + # associated scopes are now prefixed and/or suffixed accordingly: # - # class Invoice < ActiveRecord::Base - # enum verification: [:done, :fail], enum_prefix: :verification_status - # end + # conversation.active_status! + # conversation.archived_status? # => false # - # Note that <tt>:enum_prefix</tt>/<tt>:enum_suffix</tt> are reserved keywords - # and can not be used as an enum name. + # conversation.comments_inactive! + # conversation.comments_active? # => false module Enum def self.extended(base) # :nodoc: @@ -117,7 +118,7 @@ module ActiveRecord elsif mapping.has_value?(value) mapping.key(value) else - raise ArgumentError, "'#{value}' is not a valid #{name}" + assert_valid_value(value) end end @@ -130,6 +131,12 @@ module ActiveRecord mapping.fetch(value, value) end + 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 + protected attr_reader :name, :mapping @@ -137,8 +144,8 @@ module ActiveRecord def enum(definitions) klass = self - enum_prefix = definitions.delete(:enum_prefix) - enum_suffix = definitions.delete(:enum_suffix) + enum_prefix = definitions.delete(:_prefix) + enum_suffix = definitions.delete(:_suffix) definitions.each do |name, values| # statuses = { } enum_values = ActiveSupport::HashWithIndifferentAccess.new @@ -203,30 +210,22 @@ module ActiveRecord def detect_enum_conflict!(enum_name, method_name, klass_method = false) if klass_method && dangerous_class_method?(method_name) - raise ArgumentError, ENUM_CONFLICT_MESSAGE % { - enum: enum_name, - klass: self.name, - type: 'class', - method: method_name, - source: 'Active Record' - } + raise_conflict_error(enum_name, method_name, type: 'class') elsif !klass_method && dangerous_attribute_method?(method_name) - raise ArgumentError, ENUM_CONFLICT_MESSAGE % { - enum: enum_name, - klass: self.name, - type: 'instance', - method: method_name, - source: 'Active Record' - } + raise_conflict_error(enum_name, method_name) elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module) - raise ArgumentError, ENUM_CONFLICT_MESSAGE % { - enum: enum_name, - klass: self.name, - type: 'instance', - method: method_name, - source: 'another enum' - } + raise_conflict_error(enum_name, method_name, source: 'another enum') end end + + def raise_conflict_error(enum_name, method_name, type: 'instance', source: 'Active Record') + raise ArgumentError, ENUM_CONFLICT_MESSAGE % { + enum: enum_name, + klass: self.name, + type: type, + method: method_name, + source: source + } + end end end |