diff options
author | Godfrey Chan <godfreykfc@gmail.com> | 2014-01-27 01:39:52 -0800 |
---|---|---|
committer | Godfrey Chan <godfreykfc@gmail.com> | 2014-01-29 10:54:51 -0800 |
commit | 40f0257e05d8735d94684043ea7be7295fbbae57 (patch) | |
tree | 3f8d763cfc6d0d87b9bbc530444b632b3b31ba19 /activerecord/lib | |
parent | 7e8e91c439c1a877f867cd7ba634f7297ccef04b (diff) | |
download | rails-40f0257e05d8735d94684043ea7be7295fbbae57.tar.gz rails-40f0257e05d8735d94684043ea7be7295fbbae57.tar.bz2 rails-40f0257e05d8735d94684043ea7be7295fbbae57.zip |
`enum` now raises on "dangerous" name conflicts
Dangerous name conflicts includes instance or class method conflicts
with methods defined within `ActiveRecord::Base` but not its ancestors,
as well as conflicts with methods generated by other enums on the same
class.
Fixes #13389.
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/enum.rb | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index 53dde5e564..059bfe9a0f 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -77,10 +77,12 @@ module ActiveRecord name = name.to_sym # def self.statuses statuses end + detect_enum_conflict!(name, name.to_s.pluralize, true) klass.singleton_class.send(:define_method, name.to_s.pluralize) { enum_values } _enum_methods_module.module_eval do # def status=(value) self[:status] = statuses[value] end + klass.send(:detect_enum_conflict!, name, "#{name}=") define_method("#{name}=") { |value| if enum_values.has_key?(value) || value.blank? self[name] = enum_values[value] @@ -95,23 +97,28 @@ module ActiveRecord } # def status() statuses.key self[:status] end + klass.send(:detect_enum_conflict!, name, name) define_method(name) { enum_values.key self[name] } # def status_before_type_cast() statuses.key self[:status] end + klass.send(:detect_enum_conflict!, name, "#{name}_before_type_cast") define_method("#{name}_before_type_cast") { enum_values.key self[name] } pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index pairs.each do |value, i| enum_values[value] = i - # scope :active, -> { where status: 0 } - klass.scope value, -> { klass.where name => i } - # def active?() status == 0 end + klass.send(:detect_enum_conflict!, name, "#{value}?") define_method("#{value}?") { self[name] == i } # def active!() update! status: :active end + klass.send(:detect_enum_conflict!, name, "#{value}!") define_method("#{value}!") { update! name => value } + + # scope :active, -> { where status: 0 } + klass.send(:detect_enum_conflict!, name, value, true) + klass.scope value, -> { klass.where name => i } end DEFINED_ENUMS[name.to_s] = enum_values @@ -148,5 +155,38 @@ module ActiveRecord mod end end + + ENUM_CONFLICT_MESSAGE = \ + "You tried to define an enum named \"%{enum}\" on the model \"%{klass}\", but " \ + "this will generate a %{type} method \"%{method}\", which is already defined " \ + "by %{source}." + + 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' + } + 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' + } + 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' + } + end + end end end |