aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel')
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb18
-rw-r--r--activemodel/lib/active_model/callbacks.rb7
-rw-r--r--activemodel/lib/active_model/dirty.rb35
-rw-r--r--activemodel/lib/active_model/errors.rb3
-rw-r--r--activemodel/lib/active_model/serializers/xml.rb3
-rw-r--r--activemodel/lib/active_model/validations.rb4
-rw-r--r--activemodel/lib/active_model/validator.rb3
-rw-r--r--activemodel/test/cases/dirty_test.rb30
8 files changed, 73 insertions, 30 deletions
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index c1334069fa..f04829ef09 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -89,13 +89,20 @@ module ActiveModel
# # => 'address_id'
def define_attr_method(name, value=nil, &block)
sing = singleton_class
- sing.send :alias_method, "original_#{name}", name
+ sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
+ if method_defined?(:original_#{name})
+ undef :original_#{name}
+ end
+ alias_method :original_#{name}, :#{name}
+ eorb
if block_given?
sing.send :define_method, name, &block
else
# use eval instead of a block to work around a memory leak in dev
# mode in fcgi
- sing.class_eval "def #{name}; #{value.to_s.inspect}; end"
+ sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
+ def #{name}; #{value.to_s.inspect}; end
+ eorb
end
end
@@ -256,8 +263,13 @@ module ActiveModel
if respond_to?(generate_method)
send(generate_method, attr_name)
else
+ method_name = matcher.method_name(attr_name)
+
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__+1
- def #{matcher.method_name(attr_name)}(*args)
+ if method_defined?(:#{method_name})
+ undef :#{method_name}
+ end
+ def #{method_name}(*args)
send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
end
STR
diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb
index a7e0cf90c1..d4e98de57b 100644
--- a/activemodel/lib/active_model/callbacks.rb
+++ b/activemodel/lib/active_model/callbacks.rb
@@ -1,3 +1,4 @@
+require 'active_support/core_ext/array/wrap'
require 'active_support/callbacks'
module ActiveModel
@@ -91,7 +92,7 @@ module ActiveModel
options = callbacks.extract_options!
options = { :terminator => "result == false", :scope => [:kind, :name] }.merge(options)
- types = Array(options.delete(:only))
+ types = Array.wrap(options.delete(:only))
types = [:before, :around, :after] if types.empty?
callbacks.each do |callback|
@@ -124,10 +125,10 @@ module ActiveModel
def self.after_#{callback}(*args, &block)
options = args.extract_options!
options[:prepend] = true
- options[:if] = Array(options[:if]) << "!halted && value != false"
+ options[:if] = Array.wrap(options[:if]) << "!halted && value != false"
set_callback(:#{callback}, :after, *(args << options), &block)
end
CALLBACK
end
end
-end \ No newline at end of file
+end
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 5f02929a9d..cb67ef7270 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -1,3 +1,5 @@
+require 'active_support/hash_with_indifferent_access'
+
module ActiveModel
# <tt>ActiveModel::Dirty</tt> provides a way to track changes in your
# object in the same way as ActiveRecord does.
@@ -86,12 +88,17 @@ module ActiveModel
attribute_method_affix :prefix => 'reset_', :suffix => '!'
end
+ def initialize(*)
+ @changed_attributes = {}
+ super
+ end
+
# Do any attributes have unsaved changes?
# person.changed? # => false
# person.name = 'bob'
# person.changed? # => true
def changed?
- !changed_attributes.empty?
+ !@changed_attributes.empty?
end
# List of attributes with unsaved changes.
@@ -99,7 +106,7 @@ module ActiveModel
# person.name = 'bob'
# person.changed # => ['name']
def changed
- changed_attributes.keys
+ @changed_attributes.keys
end
# Map of changed attrs => [original value, new value].
@@ -107,7 +114,7 @@ module ActiveModel
# person.name = 'bob'
# person.changes # => { 'name' => ['bill', 'bob'] }
def changes
- changed.inject({}) { |h, attr| h[attr] = attribute_change(attr); h }
+ changed.inject(HashWithIndifferentAccess.new){ |h, attr| h[attr] = attribute_change(attr); h }
end
# Map of attributes that were changed when the model was saved.
@@ -116,33 +123,23 @@ module ActiveModel
# person.save
# person.previous_changes # => {'name' => ['bob, 'robert']}
def previous_changes
- previously_changed_attributes
+ @previously_changed
end
private
- # Map of change <tt>attr => original value</tt>.
- def changed_attributes
- @changed_attributes ||= {}
- end
-
- # Map of fields that were changed when the model was saved
- def previously_changed_attributes
- @previously_changed || {}
- end
-
# Handle <tt>*_changed?</tt> for +method_missing+.
def attribute_changed?(attr)
- changed_attributes.include?(attr)
+ @changed_attributes.include?(attr)
end
# Handle <tt>*_change</tt> for +method_missing+.
def attribute_change(attr)
- [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
+ [@changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
end
# Handle <tt>*_was</tt> for +method_missing+.
def attribute_was(attr)
- attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
+ attribute_changed?(attr) ? @changed_attributes[attr] : __send__(attr)
end
# Handle <tt>*_will_change!</tt> for +method_missing+.
@@ -153,12 +150,12 @@ module ActiveModel
rescue TypeError, NoMethodError
end
- changed_attributes[attr] = value
+ @changed_attributes[attr] = value
end
# Handle <tt>reset_*!</tt> for +method_missing+.
def reset_attribute!(attr)
- __send__("#{attr}=", changed_attributes[attr]) if attribute_changed?(attr)
+ __send__("#{attr}=", @changed_attributes[attr]) if attribute_changed?(attr)
end
end
end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index d8320275df..a9a54a90e0 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -1,3 +1,4 @@
+require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/string/inflections'
require 'active_support/ordered_hash'
@@ -206,7 +207,7 @@ module ActiveModel
full_messages = []
each do |attribute, messages|
- messages = Array(messages)
+ messages = Array.wrap(messages)
next if messages.empty?
if attribute == :base
diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb
index a185204680..c226359ea7 100644
--- a/activemodel/lib/active_model/serializers/xml.rb
+++ b/activemodel/lib/active_model/serializers/xml.rb
@@ -1,3 +1,4 @@
+require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/hash/conversions'
@@ -108,7 +109,7 @@ module ActiveModel
end
def serializable_method_attributes
- Array(options[:methods]).inject([]) do |methods, name|
+ Array.wrap(options[:methods]).inject([]) do |methods, name|
methods << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
methods
end
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index ba8648f8c9..708557f4ae 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/array/extract_options'
+require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/hash/keys'
require 'active_model/errors'
@@ -112,11 +113,10 @@ module ActiveModel
# end
# end
#
- # This usage applies to +validate_on_create+ and +validate_on_update as well+.
def validate(*args, &block)
options = args.last
if options.is_a?(Hash) && options.key?(:on)
- options[:if] = Array(options[:if])
+ options[:if] = Array.wrap(options[:if])
options[:if] << "@_on_validate == :#{options[:on]}"
end
set_callback(:validate, *args, &block)
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index b61f0cb266..b7c52be3f0 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -1,3 +1,4 @@
+require 'active_support/core_ext/array/wrap'
require "active_support/core_ext/module/anonymous"
module ActiveModel #:nodoc:
@@ -130,7 +131,7 @@ module ActiveModel #:nodoc:
# +options+ reader, however the <tt>:attributes</tt> option will be removed
# and instead be made available through the +attributes+ reader.
def initialize(options)
- @attributes = Array(options.delete(:attributes))
+ @attributes = Array.wrap(options.delete(:attributes))
raise ":attributes cannot be blank" if @attributes.empty?
super
check_validity!
diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb
new file mode 100644
index 0000000000..0883363baf
--- /dev/null
+++ b/activemodel/test/cases/dirty_test.rb
@@ -0,0 +1,30 @@
+require "cases/helper"
+
+class DirtyTest < ActiveModel::TestCase
+ class DirtyModel
+ include ActiveModel::Dirty
+ define_attribute_methods [:name]
+
+ def initialize
+ super
+ @name = nil
+ end
+
+ def name
+ @name
+ end
+
+ def name=(val)
+ name_will_change!
+ @name = val
+ end
+ end
+
+ test "changes accessible through both strings and symbols" do
+ model = DirtyModel.new
+ model.name = "David"
+ assert !model.changes[:name].nil?
+ assert !model.changes['name'].nil?
+ end
+
+end