aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib
diff options
context:
space:
mode:
authorlulalala <mark@goodlife.tw>2018-03-15 16:13:18 +0800
committerlulalala <mark@goodlife.tw>2019-03-31 22:59:12 +0800
commitef68d3e35cb58f9f491993eeec6e7de99442dd06 (patch)
tree04da4aac2ecb80d9c0a7aa170c4110b29308a8b8 /activemodel/lib
parentdb0256cad7487e7b8cc5f0640e0c8144d6b5d23f (diff)
downloadrails-ef68d3e35cb58f9f491993eeec6e7de99442dd06.tar.gz
rails-ef68d3e35cb58f9f491993eeec6e7de99442dd06.tar.bz2
rails-ef68d3e35cb58f9f491993eeec6e7de99442dd06.zip
Add ActiveModel::Error and NestedError
Add initialize_dup to deep dup. Move proc eval and flexible message position out to Errors, because proc eval is needed for Errors#added? and Errors#delete
Diffstat (limited to 'activemodel/lib')
-rw-r--r--activemodel/lib/active_model/error.rb60
-rw-r--r--activemodel/lib/active_model/errors.rb16
-rw-r--r--activemodel/lib/active_model/nested_error.rb33
3 files changed, 93 insertions, 16 deletions
diff --git a/activemodel/lib/active_model/error.rb b/activemodel/lib/active_model/error.rb
new file mode 100644
index 0000000000..214a0b356d
--- /dev/null
+++ b/activemodel/lib/active_model/error.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module ActiveModel
+ # == Active \Model \Error
+ #
+ # Represents one single error
+ class Error
+ CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
+ MESSAGE_OPTIONS = [:message]
+
+ def initialize(base, attribute, type, **options)
+ @base = base
+ @attribute = attribute
+ @raw_type = type
+ @type = type || :invalid
+ @options = options
+ end
+
+ def initialize_dup(other)
+ @attribute = @attribute.dup
+ @raw_type = @raw_type.dup
+ @type = @type.dup
+ @options = @options.deep_dup
+ end
+
+ attr_reader :base, :attribute, :type, :raw_type, :options
+
+ def message
+ case raw_type
+ when Symbol
+ base.errors.generate_message(attribute, raw_type, options.except(*CALLBACKS_OPTIONS))
+ else
+ raw_type
+ end
+ end
+
+ def detail
+ { error: raw_type }.merge(options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS))
+ end
+
+ def full_message
+ base.errors.full_message(attribute, message)
+ end
+
+ # See if error matches provided +attribute+, +type+ and +options+.
+ def match?(attribute, type = nil, **options)
+ if @attribute != attribute || (type && @type != type)
+ return false
+ end
+
+ options.each do |key, value|
+ if @options[key] != value
+ return false
+ end
+ end
+
+ true
+ end
+ end
+end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 3a692a3e64..7eff374ce3 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -59,9 +59,6 @@ module ActiveModel
class Errors
include Enumerable
- CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
- MESSAGE_OPTIONS = [:message]
-
class << self
attr_accessor :i18n_customize_full_message # :nodoc:
end
@@ -532,19 +529,6 @@ module ActiveModel
end
private
- def normalize_message(attribute, message, options)
- case message
- when Symbol
- generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
- else
- message
- end
- end
-
- def normalize_detail(message, options)
- { error: message }.merge(options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS))
- end
-
def without_default_proc(hash)
hash.dup.tap do |new_h|
new_h.default_proc = nil
diff --git a/activemodel/lib/active_model/nested_error.rb b/activemodel/lib/active_model/nested_error.rb
new file mode 100644
index 0000000000..b01447ac75
--- /dev/null
+++ b/activemodel/lib/active_model/nested_error.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require "active_model/error"
+require "forwardable"
+
+module ActiveModel
+ # Represents one single error
+ # @!attribute [r] base
+ # @return [ActiveModel::Base] the object which the error belongs to
+ # @!attribute [r] attribute
+ # @return [Symbol] attribute of the object which the error belongs to
+ # @!attribute [r] type
+ # @return [Symbol] error's type
+ # @!attribute [r] options
+ # @return [Hash] additional options
+ # @!attribute [r] inner_error
+ # @return [Error] inner error
+ class NestedError < Error
+ def initialize(base, inner_error, override_options = {})
+ @base = base
+ @inner_error = inner_error
+ @attribute = override_options.fetch(:attribute) { inner_error.attribute }
+ @type = override_options.fetch(:type) { inner_error.type }
+ @raw_type = inner_error.raw_type
+ @options = inner_error.options
+ end
+
+ attr_reader :inner_error
+
+ extend Forwardable
+ def_delegators :@inner_error, :full_message, :message
+ end
+end