aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/lib')
-rw-r--r--activemodel/lib/active_model.rb1
-rw-r--r--activemodel/lib/active_model/attribute_assignment.rb63
-rw-r--r--activemodel/lib/active_model/dirty.rb6
-rw-r--r--activemodel/lib/active_model/errors.rb3
-rw-r--r--activemodel/lib/active_model/locale/en.yml2
-rw-r--r--activemodel/lib/active_model/model.rb7
-rw-r--r--activemodel/lib/active_model/validator.rb4
7 files changed, 79 insertions, 7 deletions
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb
index 46d60db756..58fe08cc11 100644
--- a/activemodel/lib/active_model.rb
+++ b/activemodel/lib/active_model.rb
@@ -28,6 +28,7 @@ require 'active_model/version'
module ActiveModel
extend ActiveSupport::Autoload
+ autoload :AttributeAssignment
autoload :AttributeMethods
autoload :BlockValidator, 'active_model/validator'
autoload :Callbacks
diff --git a/activemodel/lib/active_model/attribute_assignment.rb b/activemodel/lib/active_model/attribute_assignment.rb
new file mode 100644
index 0000000000..356421476c
--- /dev/null
+++ b/activemodel/lib/active_model/attribute_assignment.rb
@@ -0,0 +1,63 @@
+require 'active_support/core_ext/hash/keys'
+
+module ActiveModel
+ module AttributeAssignment
+ include ActiveModel::ForbiddenAttributesProtection
+
+ # Allows you to set all the attributes by passing in a hash of attributes with
+ # keys matching the attribute names.
+ #
+ # If the passed hash responds to <tt>permitted?</tt> method and the return value
+ # of this method is +false+ an <tt>ActiveModel::ForbiddenAttributesError</tt>
+ # exception is raised.
+ #
+ # class Cat
+ # include ActiveModel::AttributeAssignment
+ # attr_accessor :name, :status
+ # end
+ #
+ # cat = Cat.new
+ # cat.assign_attributes(name: "Gorby", status: "yawning")
+ # cat.name # => 'Gorby'
+ # cat.status => 'yawning'
+ # cat.assign_attributes(status: "sleeping")
+ # cat.name # => 'Gorby'
+ # cat.status => 'sleeping'
+ def assign_attributes(new_attributes)
+ if !new_attributes.respond_to?(:stringify_keys)
+ raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
+ end
+ return if new_attributes.blank?
+
+ attributes = new_attributes.stringify_keys
+ _assign_attributes(sanitize_for_mass_assignment(attributes))
+ end
+
+ private
+
+ def _assign_attributes(attributes)
+ attributes.each do |k, v|
+ _assign_attribute(k, v)
+ end
+ end
+
+ def _assign_attribute(k, v)
+ if respond_to?("#{k}=")
+ public_send("#{k}=", v)
+ else
+ raise UnknownAttributeError.new(self, k)
+ end
+ end
+
+ # Raised when unknown attributes are supplied via mass assignment.
+ class UnknownAttributeError < NoMethodError
+ attr_reader :record, :attribute
+
+ def initialize(record, attribute)
+ @record = record
+ @attribute = attribute
+ super("unknown attribute '#{attribute}' for #{@record.class}.")
+ end
+ end
+ end
+end
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 614bc6a5d8..977cccf5d0 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -26,6 +26,10 @@ module ActiveModel
#
# define_attribute_methods :name
#
+ # def initialize(name = nil)
+ # @name = name
+ # end
+ #
# def name
# @name
# end
@@ -54,7 +58,7 @@ module ActiveModel
#
# A newly instantiated object is unchanged:
#
- # person = Person.find_by(name: 'Uncle Bob')
+ # person = Person.new 'Uncle Bob'
# person.changed? # => false
#
# Change the name:
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 912448e43c..a809c72ccd 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -2,6 +2,7 @@
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/string/inflections'
+require 'active_support/core_ext/object/deep_dup'
module ActiveModel
# == Active \Model \Errors
@@ -77,7 +78,7 @@ module ActiveModel
def initialize_dup(other) # :nodoc:
@messages = other.messages.dup
- @details = other.details.dup
+ @details = other.details.deep_dup
super
end
diff --git a/activemodel/lib/active_model/locale/en.yml b/activemodel/lib/active_model/locale/en.yml
index bf07945fe1..b11c8f53b4 100644
--- a/activemodel/lib/active_model/locale/en.yml
+++ b/activemodel/lib/active_model/locale/en.yml
@@ -16,7 +16,7 @@ en:
present: "must be blank"
too_long:
one: "is too long (maximum is 1 character)"
- other: "is too long (maximum is %{count} characters)"
+ other: "is too long (maximum is %{count} characters)"
too_short:
one: "is too short (minimum is 1 character)"
other: "is too short (minimum is %{count} characters)"
diff --git a/activemodel/lib/active_model/model.rb b/activemodel/lib/active_model/model.rb
index d51d6ddcc9..dac8d549a7 100644
--- a/activemodel/lib/active_model/model.rb
+++ b/activemodel/lib/active_model/model.rb
@@ -57,6 +57,7 @@ module ActiveModel
# (see below).
module Model
extend ActiveSupport::Concern
+ include ActiveModel::AttributeAssignment
include ActiveModel::Validations
include ActiveModel::Conversion
@@ -75,10 +76,8 @@ module ActiveModel
# person = Person.new(name: 'bob', age: '18')
# person.name # => "bob"
# person.age # => "18"
- def initialize(params={})
- params.each do |attr, value|
- self.public_send("#{attr}=", value)
- end if params
+ def initialize(attributes={})
+ assign_attributes(attributes) if attributes
super()
end
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index ac32750946..b98585912e 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -163,6 +163,10 @@ module ActiveModel
# +ArgumentError+ when invalid options are supplied.
def check_validity!
end
+
+ def should_validate?(record) # :nodoc:
+ !record.persisted? || record.changed? || record.marked_for_destruction?
+ end
end
# +BlockValidator+ is a special +EachValidator+ which receives a block on initialization