Permalink
Browse files

Make enum feature work with dirty methods

To make this possible we have to override the save_changed_attribute
hook.
  • Loading branch information...
1 parent a4cc88d commit a57a2bcf4a2c29519d553277e4439790ca443cc7 @rafaelfranca rafaelfranca committed Jan 20, 2014
Showing with 76 additions and 1 deletion.
  1. +18 −0 activerecord/CHANGELOG.md
  2. +18 −1 activerecord/lib/active_record/enum.rb
  3. +40 −0 activerecord/test/cases/enum_test.rb
View
@@ -1,3 +1,21 @@
+* Make enum fields work as expected with the `ActiveModel::Dirty` API.
+
+ Before this change, using the dirty API would have surprising results:
+
+ conversation = Conversation.new
+ conversation.status = :active
+ conversation.status = :archived
+ conversation.status_was # => 0
+
+ After this change, the same code would result in:
+
+ conversation = Conversation.new
+ conversation.status = :active
+ conversation.status = :archived
+ conversation.status_was # => "active"
+
+ *Rafael Mendonça França*
+
* Ensure `second` through `fifth` methods act like the `first` finder.
The famous ordinal Array instance methods defined in ActiveSupport
@@ -63,13 +63,21 @@ module ActiveRecord
#
# Conversation.where("status <> ?", Conversation.statuses[:archived])
module Enum
+ DEFINED_ENUMS = [] # :nodoc:
+
+ def enum_attribute?(attr_name) # :nodoc:
+ DEFINED_ENUMS.include?(attr_name.to_sym)
+ end
+
def enum(definitions)
klass = self
definitions.each do |name, values|
# statuses = { }
enum_values = ActiveSupport::HashWithIndifferentAccess.new
name = name.to_sym
+ DEFINED_ENUMS.unshift name
+
# def self.statuses statuses end
klass.singleton_class.send(:define_method, name.to_s.pluralize) { enum_values }
@@ -114,7 +122,16 @@ def enum(definitions)
private
def _enum_methods_module
@_enum_methods_module ||= begin
- mod = Module.new
+ mod = Module.new do
+ def save_changed_attribute(attr_name, value)
+ if self.class.enum_attribute?(attr_name)
+ old = clone_attribute_value(:read_attribute, attr_name)
+ changed_attributes[attr_name] = self.class.public_send(attr_name.pluralize).key old
+ else
+ super
+ end
+ end
+ end
include mod
mod
end
@@ -51,6 +51,46 @@ class EnumTest < ActiveRecord::TestCase
assert @book.written?
end
+ test "enum changed attributes" do
+ old_status = @book.status
+ @book.status = :published
+ assert_equal old_status, @book.changed_attributes[:status]
+ end
+
+ test "enum changes" do
+ old_status = @book.status
+ @book.status = :published
+ assert_equal [old_status, 'published'], @book.changes[:status]
+ end
+
+ test "enum attribute was" do
+ old_status = @book.status
+ @book.status = :published
+ assert_equal old_status, @book.attribute_was(:status)
+ end
+
+ test "enum attribute changed" do
+ @book.status = :published
+ assert @book.attribute_changed?(:status)
+ end
+
+ test "enum attribute changed to" do
+ @book.status = :published
+ assert @book.attribute_changed?(:status, to: 'published')
+ end
+
+ test "enum attribute changed from" do
+ old_status = @book.status
+ @book.status = :published
+ assert @book.attribute_changed?(:status, from: old_status)
+ end
+
+ test "enum attribute changed from old status to new status" do
+ old_status = @book.status
+ @book.status = :published
+ assert @book.attribute_changed?(:status, from: old_status, to: 'published')
+ end
+
test "assign non existing value raises an error" do
e = assert_raises(ArgumentError) do
@book.status = :unknown

0 comments on commit a57a2bc

Please sign in to comment.