option to disable all methods that ActiveRecord.enum generates

This commit is contained in:
Alfred Dominic 2022-11-13 13:01:22 +05:30
parent 3bb8cb9204
commit 61b8253387
3 changed files with 28 additions and 11 deletions

@ -1,3 +1,7 @@
* Allow disabling methods generated by `ActiveRecord.enum`.
*Alfred Dominic*
* Avoid validating `belongs_to` association if it has not changed.
Previously, when updating a record, Active Record will perform an extra query to check for the presence of

@ -179,14 +179,14 @@ def enum(name = nil, values = nil, **options)
return _enum(name, values, **options)
end
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default)
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default, :_instance_methods)
options.transform_keys! { |key| :"#{key[1..-1]}" }
definitions.each { |name, values| _enum(name, values, **options) }
end
private
def _enum(name, values, prefix: nil, suffix: nil, scopes: true, **options)
def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, **options)
assert_valid_enum_definition_values(values)
# statuses = { }
enum_values = ActiveSupport::HashWithIndifferentAccess.new
@ -222,14 +222,14 @@ def _enum(name, values, prefix: nil, suffix: nil, scopes: true, **options)
value_method_name = "#{prefix}#{label}#{suffix}"
value_method_names << value_method_name
define_enum_methods(name, value_method_name, value, scopes)
define_enum_methods(name, value_method_name, value, scopes, instance_methods)
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
value_method_names << value_method_alias
define_enum_methods(name, value_method_alias, value, scopes)
define_enum_methods(name, value_method_alias, value, scopes, instance_methods)
end
end
end
@ -245,14 +245,16 @@ def initialize(klass)
private
attr_reader :klass
def define_enum_methods(name, value_method_name, value, scopes)
# def active?() status_for_database == 0 end
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
def define_enum_methods(name, value_method_name, value, scopes, instance_methods)
if instance_methods
# def active?() status_for_database == 0 end
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
# def active!() update!(status: 0) end
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
define_method("#{value_method_name}!") { update!(name => value) }
# def active!() update!(status: 0) end
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
define_method("#{value_method_name}!") { update!(name => value) }
end
# scope :active, -> { where(status: 0) }
# scope :not_active, -> { where.not(status: 0) }

@ -1020,4 +1020,15 @@ def self.name
end
assert_equal "Unknown enum attribute 'columnless_genre' for Book", error.message
end
test "default methods can be disabled by :_instance_methods" do
klass = Class.new(ActiveRecord::Base) do
self.table_name = "books"
enum status: [:proposed, :written], _instance_methods: false
end
instance = klass.new
assert_raises(NoMethodError) { instance.proposed? }
assert_raises(NoMethodError) { instance.proposed! }
end
end