diff --git a/lib/attr_default.rb b/lib/attr_default.rb index 289eac1..7b64039 100644 --- a/lib/attr_default.rb +++ b/lib/attr_default.rb @@ -88,32 +88,44 @@ def write_attribute_with_fixups(attr_name, args) def needs_time_zone_fixup?(attr_name) self.class.send(:create_time_zone_conversion_attribute?, attr_name, self.class.columns_hash[attr_name]) end + + def copy(opts = {}) + if opts.key? :new_record + if opts[:new_record] + result = if defined?(super) + super(opts) + else + copy_new_record_true + end + + result.created_at = nil unless !result.class.columns_hash.has_key?('created_at') + result.updated_at = nil unless !result.class.columns_hash.has_key?('updated_at') + if self.new_record? + result.instance_variable_set(:@_attr_default_set, self._attr_default_set.dup) + else + result.instance_variable_set(:@_attr_defaults_set_from_dup, true) + end - if Gem.loaded_specs['activesupport'].version >= Gem::Version.new('3.1') - def dup - result = super - result.created_at = nil unless !result.class.columns_hash.has_key?('created_at') - result.updated_at = nil unless !result.class.columns_hash.has_key?('updated_at') - if self.new_record? - result.instance_variable_set(:@_attr_default_set, self._attr_default_set.dup) + result else - result.instance_variable_set(:@_attr_defaults_set_from_dup, true) + if defined?(super) + super(opts) + else + copy_new_record_false # self.dup # what kind of default logic do we wire in + end end - result + else + # eventually phase this out with required keywords in ruby 2.0 + raise ArgumentError, "Ambiguous call to copy please provide :new_record => (true|false)" end - alias_method(:clone, :dup) + end + + if Gem.loaded_specs['activesupport'].version >= Gem::Version.new('3.1') + alias :copy_new_record_true :dup + alias :copy_new_record_false :clone else - def clone - result = super - result.created_at = nil unless !result.class.columns_hash.has_key?('created_at') - result.updated_at = nil unless !result.class.columns_hash.has_key?('updated_at') - if self.new_record? - result.instance_variable_set(:@_attr_default_set, self._attr_default_set.dup) - else - result.instance_variable_set(:@_attr_defaults_set_from_dup, true) - end - result - end + alias :copy_new_record_true :clone + alias :copy_new_record_false :dup end end end diff --git a/test/attr_default_test.rb b/test/attr_default_test.rb index 890b7a1..0157d78 100644 --- a/test/attr_default_test.rb +++ b/test/attr_default_test.rb @@ -24,14 +24,7 @@ false end -DUP_METHODS = - if Gem.loaded_specs['activesupport'].version >= Gem::Version.new('4.0') - [:dup] - elsif Gem.loaded_specs['activesupport'].version >= Gem::Version.new('3.1') - [:dup, :clone] - else - [:clone] - end +COPY_METHODS = [:copy] File.unlink('test.sqlite3') rescue nil ActiveRecord::Base.logger = Logger.new(STDERR) @@ -220,27 +213,28 @@ def test_use_default_when_saved_if_not_touched assert_equal "initial.com", domain.domain end - def test_dup_and_clone_touched_state_when_duped_or_cloned_before_save_new_record_true - DUP_METHODS.each do |dup| + def test_copy_touched_state_when_copied_before_save_new_record_true + COPY_METHODS.each do |copy| u = TestUser.new :first_name => 'John', :last_name => 'Doe' u.last_name = 'overridden' - u2 = u.send(dup) + u2 = u.send(copy, :new_record => true) assert_equal 'overridden', u2.read_attribute(:last_name) assert_equal 'overridden', u2.last_name end end - def test_dup_and_clone_touched_state_when_duped_or_cloned_after_save_new_record_false - DUP_METHODS.each do |dup| + # This test is referring to the record itself returning false from #new_record? after being "cloned" i.e copy(new_record: true) + def test_copy_touched_state_when_copied_after_save_new_record_false + COPY_METHODS.each do |copy| u = TestUser.new(:first_name => 'John', :last_name => 'Doe') u.last_name = 'overridden' - u2 = u.send(dup) + u2 = u.send(copy, :new_record => true) u2.save! u.save! - assert u.send(dup).instance_variable_get(:@_attr_defaults_set_from_dup) - assert_equal 'overridden', u.send(dup).last_name + assert u.send(copy, :new_record => true).instance_variable_get(:@_attr_defaults_set_from_dup) + assert_equal 'overridden', u.send(copy, :new_record => true).last_name ufind = TestUser.find(u.id) - u3 = ufind.send(dup) + u3 = ufind.send(copy, :new_record => true) assert_equal 'overridden', u3.read_attribute(:last_name), u3.attributes.inspect assert_equal 'overridden', u3.last_name u3.save!