Skip to content

Commit

Permalink
Merge branch 'active-model-dirty'
Browse files Browse the repository at this point in the history
  • Loading branch information
beerlington committed Oct 24, 2014
2 parents 0e7f44f + 9a0fe92 commit 6bd7d40
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@
* [BREAKING] Removed use of null objects. Blank values are now returned as is from Enum.build.
* [BREAKING] Removed serialize_as_json option. #as_json should be overriden in ClassyEnum::Base subclasses instead.
* [BREAKING] Removed allow_blank option from Enum.build. This was used internally for legacy reasons and is no longer needed.
* [BREAKING] Fixes support for ActiveModel::Dirty. Now dirty attribute methods always return enum class instance (instead of string).
* Prefer 'class_name' over 'enum' as optional class name argument

## 3.5.0
Expand Down
40 changes: 32 additions & 8 deletions lib/classy_enum/active_record.rb
Expand Up @@ -67,17 +67,41 @@ def classy_enum_attr(attribute, options={})
allow_blank: allow_blank,
allow_nil: allow_nil

# Define getter method that returns a ClassyEnum instance
define_method attribute do
enum.build(read_attribute(attribute), owner: self)
end
# Use a module so that the reader methods can be overridden in classes and
# use super to get the enum value.
mod = Module.new do

# Define getter method that returns a ClassyEnum instance
define_method attribute do
enum.build(read_attribute(attribute), owner: self)
end

# Define setter method that accepts string, symbol, instance or class for member
define_method "#{attribute}=" do |value|
value = ClassyEnum._normalize_value(value, default, (allow_nil || allow_blank))
super(value)
end

# Define setter method that accepts string, symbol, instance or class for member
define_method "#{attribute}=" do |value|
value = ClassyEnum._normalize_value(value, default, (allow_nil || allow_blank))
super(value)
define_method :save_changed_attribute do |attr_name, arg|
if attribute.to_s == attr_name.to_s && !attribute_changed?(attr_name)
arg = enum.build(arg)
current_value = clone_attribute_value(:read_attribute, attr_name)

if arg != current_value
if respond_to?(:set_attribute_was, true)
set_attribute_was(attr_name, enum.build(arg, owner: self))
else
changed_attributes[attr_name] = enum.build(current_value, owner: self)
end
end
else
super(attr_name, arg)
end
end
end

include mod

# Initialize the object with the default value if it is present
# because this will let you store the default value in the
# database and make it searchable.
Expand Down
72 changes: 72 additions & 0 deletions spec/classy_enum/active_record_spec.rb
Expand Up @@ -79,6 +79,78 @@ class OtherDog < Dog
end
end

if ::ActiveRecord::VERSION::MAJOR == 4 && ::ActiveRecord::VERSION::MINOR > 0
context "works with ActiveModel's attributes" do
subject { DefaultDog.create(breed: :golden_retriever) }
let(:old_breed) { Breed::GoldenRetriever.new }

it "sets changed_attributes to enum object" do
subject.breed = :snoop
subject.changed_attributes[:breed].should eq(old_breed)
end

it "sets changes to array" do
subject.breed = :snoop
subject.changes[:breed].should eq([old_breed, :snoop])
end

it "works with attribute_changed?" do
subject.breed = :snoop
subject.breed_was.should eq(old_breed)
subject.breed_changed?.should be_true

if subject.respond_to? :attribute_changed?
subject.attribute_changed?(:breed, to: Breed::Snoop.new).should be_true
subject.breed_changed?(
from: Breed::GoldenRetriever.new,
to: Breed::Snoop.new
).should be_true
end
end

it "returns enum object for *_was" do
subject.breed = :snoop
subject.breed_was.golden_retriever?.should be_true
end

it "reverts changes" do
subject.breed = :snoop
subject.breed_changed?.should be_true
subject.breed = old_breed
subject.breed_changed?.should be_false
end

it "does not track the same value" do
subject.breed = :golden_retriever
subject.breed_changed?.should be_false
end

it "retains changes with multiple assignments" do
subject.breed = :snoop
subject.breed_changed?.should be_true
subject.breed = :husky
subject.breed_changed?.should be_true
end

it "allows tracks changes when nil is allowed" do
dog = AllowNilBreedDog.create(breed: :snoop)
dog.breed = nil
dog.save!
dog.breed = :snoop
dog.breed_changed?.should be_true
dog.breed = nil
dog.breed_changed?.should be_false
end

it "restores breed (Rails 4.2+)" do
if subject.respond_to?(:restore_breed)
subject.restore_breed!
subject.breed.should eq(:golden_retriever)
end
end
end
end

context "with invalid breed options" do
subject { DefaultDog.new(breed: :fake_breed) }
it { should_not be_valid }
Expand Down

0 comments on commit 6bd7d40

Please sign in to comment.