ae-validates_timeliness 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Appraisals +11 -0
- data/CHANGELOG.rdoc +190 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +178 -0
- data/LICENSE +20 -0
- data/README.md +329 -0
- data/Rakefile +30 -0
- data/ae-validates_timeliness.gemspec +25 -0
- data/autotest/discover.rb +1 -0
- data/gemfiles/rails_4_0.gemfile +15 -0
- data/gemfiles/rails_4_0.gemfile.lock +152 -0
- data/gemfiles/rails_4_1.gemfile +15 -0
- data/gemfiles/rails_4_1.gemfile.lock +156 -0
- data/gemfiles/rails_4_2.gemfile +15 -0
- data/gemfiles/rails_4_2.gemfile.lock +178 -0
- data/init.rb +1 -0
- data/lib/ae-validates_timeliness.rb +1 -0
- data/lib/ae-validates_timeliness/version.rb +3 -0
- data/lib/generators/validates_timeliness/install_generator.rb +16 -0
- data/lib/generators/validates_timeliness/templates/en.yml +16 -0
- data/lib/generators/validates_timeliness/templates/validates_timeliness.rb +40 -0
- data/lib/validates_timeliness.rb +70 -0
- data/lib/validates_timeliness/attribute_methods.rb +97 -0
- data/lib/validates_timeliness/conversion.rb +70 -0
- data/lib/validates_timeliness/extensions.rb +14 -0
- data/lib/validates_timeliness/extensions/date_time_select.rb +61 -0
- data/lib/validates_timeliness/extensions/multiparameter_handler.rb +80 -0
- data/lib/validates_timeliness/helper_methods.rb +23 -0
- data/lib/validates_timeliness/orm/active_record.rb +94 -0
- data/lib/validates_timeliness/orm/mongoid.rb +63 -0
- data/lib/validates_timeliness/railtie.rb +15 -0
- data/lib/validates_timeliness/validator.rb +117 -0
- metadata +159 -0
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'validates_timeliness'
|
@@ -0,0 +1 @@
|
|
1
|
+
require "validates_timeliness"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
desc "Copy ValidatesTimeliness default files"
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
|
7
|
+
def copy_initializers
|
8
|
+
copy_file 'validates_timeliness.rb', 'config/initializers/validates_timeliness.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
def copy_locale_file
|
12
|
+
copy_file 'en.yml', 'config/locales/validates_timeliness.en.yml'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
en:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
invalid_date: "is not a valid date"
|
5
|
+
invalid_time: "is not a valid time"
|
6
|
+
invalid_datetime: "is not a valid datetime"
|
7
|
+
is_at: "must be at %{restriction}"
|
8
|
+
before: "must be before %{restriction}"
|
9
|
+
on_or_before: "must be on or before %{restriction}"
|
10
|
+
after: "must be after %{restriction}"
|
11
|
+
on_or_after: "must be on or after %{restriction}"
|
12
|
+
validates_timeliness:
|
13
|
+
error_value_formats:
|
14
|
+
date: '%Y-%m-%d'
|
15
|
+
time: '%H:%M:%S'
|
16
|
+
datetime: '%Y-%m-%d %H:%M:%S'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
ValidatesTimeliness.setup do |config|
|
2
|
+
# Extend ORM/ODMs for full support (:active_record, :mongoid).
|
3
|
+
# config.extend_orms = [ :active_record ]
|
4
|
+
#
|
5
|
+
# Default timezone
|
6
|
+
# config.default_timezone = :utc
|
7
|
+
#
|
8
|
+
# Set the dummy date part for a time type values.
|
9
|
+
# config.dummy_date_for_time_type = [ 2000, 1, 1 ]
|
10
|
+
#
|
11
|
+
# Ignore errors when restriction options are evaluated
|
12
|
+
# config.ignore_restriction_errors = false
|
13
|
+
#
|
14
|
+
# Re-display invalid values in date/time selects
|
15
|
+
# config.enable_date_time_select_extension!
|
16
|
+
#
|
17
|
+
# Handle multiparameter date/time values strictly
|
18
|
+
# config.enable_multiparameter_extension!
|
19
|
+
#
|
20
|
+
# Shorthand date and time symbols for restrictions
|
21
|
+
# config.restriction_shorthand_symbols.update(
|
22
|
+
# :now => lambda { Time.current },
|
23
|
+
# :today => lambda { Date.current }
|
24
|
+
# )
|
25
|
+
#
|
26
|
+
# Use the plugin date/time parser which is stricter and extendable
|
27
|
+
# config.use_plugin_parser = false
|
28
|
+
#
|
29
|
+
# Add one or more formats making them valid. e.g. add_formats(:date, 'd(st|rd|th) of mmm, yyyy')
|
30
|
+
# config.parser.add_formats()
|
31
|
+
#
|
32
|
+
# Remove one or more formats making them invalid. e.g. remove_formats(:date, 'dd/mm/yyy')
|
33
|
+
# config.parser.remove_formats()
|
34
|
+
#
|
35
|
+
# Change the amiguous year threshold when parsing a 2 digit year
|
36
|
+
# config.parser.ambiguous_year_threshold = 30
|
37
|
+
#
|
38
|
+
# Treat ambiguous dates, such as 01/02/1950, as a Non-US date.
|
39
|
+
# config.parser.remove_us_formats
|
40
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'active_support/concern'
|
3
|
+
require 'active_support/core_ext/module'
|
4
|
+
require 'active_support/core_ext/hash/except'
|
5
|
+
require 'active_support/core_ext/string/conversions'
|
6
|
+
require 'active_support/core_ext/date/acts_like'
|
7
|
+
require 'active_support/core_ext/date/conversions'
|
8
|
+
require 'active_support/core_ext/time/acts_like'
|
9
|
+
require 'active_support/core_ext/time/conversions'
|
10
|
+
require 'active_support/core_ext/date_time/acts_like'
|
11
|
+
require 'active_support/core_ext/date_time/conversions'
|
12
|
+
require 'timeliness'
|
13
|
+
|
14
|
+
Timeliness.module_eval do
|
15
|
+
class << self
|
16
|
+
alias :dummy_date_for_time_type :date_for_time_type
|
17
|
+
alias :dummy_date_for_time_type= :date_for_time_type=
|
18
|
+
alias :remove_us_formats :use_euro_formats
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ValidatesTimeliness
|
23
|
+
autoload :VERSION, 'validates_timeliness/version'
|
24
|
+
|
25
|
+
class << self
|
26
|
+
delegate :default_timezone, :default_timezone=, :dummy_date_for_time_type, :dummy_date_for_time_type=, :to => Timeliness
|
27
|
+
|
28
|
+
attr_accessor :extend_orms, :ignore_restriction_errors, :restriction_shorthand_symbols, :use_plugin_parser
|
29
|
+
end
|
30
|
+
|
31
|
+
# Extend ORM/ODMs for full support (:active_record, :mongoid).
|
32
|
+
self.extend_orms = []
|
33
|
+
|
34
|
+
# Ignore errors when restriction options are evaluated
|
35
|
+
self.ignore_restriction_errors = false
|
36
|
+
|
37
|
+
# Shorthand time and date symbols for restrictions
|
38
|
+
self.restriction_shorthand_symbols = {
|
39
|
+
:now => lambda { Time.current },
|
40
|
+
:today => lambda { Date.current }
|
41
|
+
}
|
42
|
+
|
43
|
+
# Use the plugin date/time parser which is stricter and extensible
|
44
|
+
self.use_plugin_parser = false
|
45
|
+
|
46
|
+
# Default timezone
|
47
|
+
self.default_timezone = :utc
|
48
|
+
|
49
|
+
# Set the dummy date part for a time type values.
|
50
|
+
self.dummy_date_for_time_type = [ 2000, 1, 1 ]
|
51
|
+
|
52
|
+
# Setup method for plugin configuration
|
53
|
+
def self.setup
|
54
|
+
yield self
|
55
|
+
load_orms
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.load_orms
|
59
|
+
extend_orms.each {|orm| require "validates_timeliness/orm/#{orm}" }
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.parser; Timeliness end
|
63
|
+
end
|
64
|
+
|
65
|
+
require 'validates_timeliness/conversion'
|
66
|
+
require 'validates_timeliness/validator'
|
67
|
+
require 'validates_timeliness/helper_methods'
|
68
|
+
require 'validates_timeliness/attribute_methods'
|
69
|
+
require 'validates_timeliness/extensions'
|
70
|
+
require 'validates_timeliness/railtie' if defined?(Rails)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
module AttributeMethods
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class << self
|
7
|
+
attr_accessor :timeliness_validated_attributes
|
8
|
+
end
|
9
|
+
self.timeliness_validated_attributes = []
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
public
|
15
|
+
# Override in ORM shim
|
16
|
+
def timeliness_attribute_timezone_aware?(attr_name)
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
# Override in ORM shim
|
21
|
+
def timeliness_attribute_type(attr_name)
|
22
|
+
:datetime
|
23
|
+
end
|
24
|
+
|
25
|
+
def undefine_attribute_methods
|
26
|
+
super
|
27
|
+
undefine_timeliness_attribute_methods
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def define_timeliness_methods(before_type_cast=false)
|
33
|
+
return if timeliness_validated_attributes.blank?
|
34
|
+
timeliness_validated_attributes.each do |attr_name|
|
35
|
+
define_attribute_timeliness_methods(attr_name, before_type_cast)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_attribute_timeliness_methods(attr_name, before_type_cast=false)
|
40
|
+
define_timeliness_write_method(attr_name)
|
41
|
+
define_timeliness_before_type_cast_method(attr_name) if before_type_cast
|
42
|
+
end
|
43
|
+
|
44
|
+
def define_timeliness_write_method(attr_name)
|
45
|
+
method_body, line = <<-EOV, __LINE__ + 1
|
46
|
+
def #{attr_name}=(value)
|
47
|
+
original_value = value
|
48
|
+
@timeliness_cache ||= {}
|
49
|
+
@timeliness_cache["#{attr_name}"] = original_value
|
50
|
+
#{ "if value.is_a?(String)\n#{timeliness_type_cast_code(attr_name, 'value')}\nend" if ValidatesTimeliness.use_plugin_parser }
|
51
|
+
|
52
|
+
super(value)
|
53
|
+
end
|
54
|
+
EOV
|
55
|
+
generated_timeliness_methods.module_eval(method_body, __FILE__, line)
|
56
|
+
end
|
57
|
+
|
58
|
+
def define_timeliness_before_type_cast_method(attr_name)
|
59
|
+
method_body, line = <<-EOV, __LINE__ + 1
|
60
|
+
def #{attr_name}_before_type_cast
|
61
|
+
_timeliness_raw_value_for('#{attr_name}') || begin
|
62
|
+
a = @attributes['#{attr_name}']
|
63
|
+
a.respond_to?(:value_before_type_cast) ? a.value_before_type_cast : a
|
64
|
+
end
|
65
|
+
end
|
66
|
+
EOV
|
67
|
+
generated_timeliness_methods.module_eval(method_body, __FILE__, line)
|
68
|
+
end
|
69
|
+
|
70
|
+
def timeliness_type_cast_code(attr_name, var_name)
|
71
|
+
type = timeliness_attribute_type(attr_name)
|
72
|
+
timezone_aware = timeliness_attribute_timezone_aware?(attr_name)
|
73
|
+
timezone = :current if timezone_aware
|
74
|
+
|
75
|
+
"#{var_name} = Timeliness::Parser.parse(#{var_name}, :#{type}, :zone => #{timezone.inspect})"
|
76
|
+
end
|
77
|
+
|
78
|
+
def generated_timeliness_methods
|
79
|
+
@generated_timeliness_methods ||= Module.new.tap { |m| include(m) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def undefine_timeliness_attribute_methods
|
83
|
+
generated_timeliness_methods.module_eval do
|
84
|
+
instance_methods.each { |m| undef_method(m) }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def _timeliness_raw_value_for(attr_name)
|
90
|
+
@timeliness_cache && @timeliness_cache[attr_name]
|
91
|
+
end
|
92
|
+
|
93
|
+
def _clear_timeliness_cache
|
94
|
+
@timeliness_cache = {}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
module Conversion
|
3
|
+
|
4
|
+
def type_cast_value(value, type)
|
5
|
+
return nil if value.nil? || !value.respond_to?(:to_time)
|
6
|
+
|
7
|
+
value = value.in_time_zone if value.acts_like?(:time) && @timezone_aware
|
8
|
+
value = case type
|
9
|
+
when :time
|
10
|
+
dummy_time(value)
|
11
|
+
when :date
|
12
|
+
value.to_date
|
13
|
+
when :datetime
|
14
|
+
value.is_a?(Time) ? value : value.to_time
|
15
|
+
end
|
16
|
+
if options[:ignore_usec] && value.is_a?(Time)
|
17
|
+
Timeliness::Parser.make_time(Array(value).reverse[4..9], (:current if @timezone_aware))
|
18
|
+
else
|
19
|
+
value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def dummy_time(value)
|
24
|
+
time = if value.acts_like?(:time)
|
25
|
+
value = value.in_time_zone if @timezone_aware
|
26
|
+
[value.hour, value.min, value.sec]
|
27
|
+
else
|
28
|
+
[0,0,0]
|
29
|
+
end
|
30
|
+
values = ValidatesTimeliness.dummy_date_for_time_type + time
|
31
|
+
Timeliness::Parser.make_time(values, (:current if @timezone_aware))
|
32
|
+
end
|
33
|
+
|
34
|
+
def evaluate_option_value(value, record)
|
35
|
+
case value
|
36
|
+
when Time, Date
|
37
|
+
value
|
38
|
+
when String
|
39
|
+
parse(value)
|
40
|
+
when Symbol
|
41
|
+
if !record.respond_to?(value) && restriction_shorthand?(value)
|
42
|
+
ValidatesTimeliness.restriction_shorthand_symbols[value].call
|
43
|
+
else
|
44
|
+
evaluate_option_value(record.send(value), record)
|
45
|
+
end
|
46
|
+
when Proc
|
47
|
+
result = value.arity > 0 ? value.call(record) : value.call
|
48
|
+
evaluate_option_value(result, record)
|
49
|
+
else
|
50
|
+
value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def restriction_shorthand?(symbol)
|
55
|
+
ValidatesTimeliness.restriction_shorthand_symbols.keys.include?(symbol)
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse(value)
|
59
|
+
return nil if value.nil?
|
60
|
+
if ValidatesTimeliness.use_plugin_parser
|
61
|
+
Timeliness::Parser.parse(value, @type, :zone => (:current if @timezone_aware), :format => options[:format], :strict => false)
|
62
|
+
else
|
63
|
+
@timezone_aware ? Time.zone.parse(value, Time.zone.now) : value.to_time(ValidatesTimeliness.default_timezone)
|
64
|
+
end
|
65
|
+
rescue ArgumentError, TypeError
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
module Extensions
|
3
|
+
autoload :DateTimeSelect, 'validates_timeliness/extensions/date_time_select'
|
4
|
+
autoload :MultiparameterHandler, 'validates_timeliness/extensions/multiparameter_handler'
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.enable_date_time_select_extension!
|
8
|
+
::ActionView::Helpers::InstanceTag.send(:include, ValidatesTimeliness::Extensions::DateTimeSelect)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.enable_multiparameter_extension!
|
12
|
+
::ActiveRecord::Base.send(:include, ValidatesTimeliness::Extensions::MultiparameterHandler)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
module Extensions
|
3
|
+
module DateTimeSelect
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
# Intercepts the date and time select helpers to reuse the values from
|
7
|
+
# the params rather than the parsed value. This allows invalid date/time
|
8
|
+
# values to be redisplayed instead of blanks to aid correction by the user.
|
9
|
+
# It's a minor usability improvement which is rarely an issue for the user.
|
10
|
+
|
11
|
+
included do
|
12
|
+
alias_method_chain :datetime_selector, :timeliness
|
13
|
+
alias_method_chain :value, :timeliness
|
14
|
+
end
|
15
|
+
|
16
|
+
class TimelinessDateTime
|
17
|
+
attr_accessor :year, :month, :day, :hour, :min, :sec
|
18
|
+
|
19
|
+
def initialize(year, month, day, hour, min, sec)
|
20
|
+
@year, @month, @day, @hour, @min, @sec = year, month, day, hour, min, sec
|
21
|
+
end
|
22
|
+
|
23
|
+
# adapted from activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 36 (3.0.7)
|
24
|
+
def change(options)
|
25
|
+
TimelinessDateTime.new(
|
26
|
+
options[:year] || year,
|
27
|
+
options[:month] || month,
|
28
|
+
options[:day] || day,
|
29
|
+
options[:hour] || hour,
|
30
|
+
options[:min] || (options[:hour] ? 0 : min),
|
31
|
+
options[:sec] || ((options[:hour] || options[:min]) ? 0 : sec)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def datetime_selector_with_timeliness(*args)
|
37
|
+
@timeliness_date_or_time_tag = true
|
38
|
+
datetime_selector_without_timeliness(*args)
|
39
|
+
end
|
40
|
+
|
41
|
+
def value_with_timeliness(object)
|
42
|
+
unless @timeliness_date_or_time_tag && @template_object.params[@object_name]
|
43
|
+
return value_without_timeliness(object)
|
44
|
+
end
|
45
|
+
|
46
|
+
@template_object.params[@object_name]
|
47
|
+
|
48
|
+
pairs = @template_object.params[@object_name].select {|k,v| k =~ /^#{@method_name}\(/ }
|
49
|
+
return value_without_timeliness(object) if pairs.empty?
|
50
|
+
|
51
|
+
values = [nil] * 6
|
52
|
+
pairs.map do |(param, value)|
|
53
|
+
position = param.scan(/\((\d+)\w+\)/).first.first
|
54
|
+
values[position.to_i-1] = value.to_i
|
55
|
+
end
|
56
|
+
|
57
|
+
TimelinessDateTime.new(*values)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
module Extensions
|
3
|
+
module MultiparameterHandler
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
# Stricter handling of date and time values from multiparameter
|
7
|
+
# assignment from the date/time select view helpers
|
8
|
+
|
9
|
+
included do
|
10
|
+
alias_method_chain :instantiate_time_object, :timeliness
|
11
|
+
alias_method :execute_callstack_for_multiparameter_attributes, :execute_callstack_for_multiparameter_attributes_with_timeliness
|
12
|
+
alias_method :read_value_from_parameter, :read_value_from_parameter_with_timeliness
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def invalid_multiparameter_date_or_time_as_string(values)
|
18
|
+
value = [values[0], *values[1..2].map {|s| s.to_s.rjust(2,"0")} ].join("-")
|
19
|
+
value += ' ' + values[3..5].map {|s| s.to_s.rjust(2, "0") }.join(":") unless values[3..5].empty?
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
def instantiate_time_object_with_timeliness(name, values)
|
24
|
+
validate_multiparameter_date_values(values) {
|
25
|
+
instantiate_time_object_without_timeliness(name, values)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def instantiate_date_object(name, values)
|
30
|
+
validate_multiparameter_date_values(values) {
|
31
|
+
Date.new(*values)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
# Yield if date values are valid
|
36
|
+
def validate_multiparameter_date_values(values)
|
37
|
+
if values[0..2].all?{ |v| v.present? } && Date.valid_civil?(*values[0..2])
|
38
|
+
yield
|
39
|
+
else
|
40
|
+
invalid_multiparameter_date_or_time_as_string(values)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def read_value_from_parameter_with_timeliness(name, values_from_param)
|
45
|
+
klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass
|
46
|
+
values = values_from_param.is_a?(Hash) ? values_from_param.to_a.sort_by(&:first).map(&:last) : values_from_param
|
47
|
+
|
48
|
+
if values.empty? || values.all?{ |v| v.nil? }
|
49
|
+
nil
|
50
|
+
elsif klass == Time
|
51
|
+
instantiate_time_object(name, values)
|
52
|
+
elsif klass == Date
|
53
|
+
instantiate_date_object(name, values)
|
54
|
+
else
|
55
|
+
if respond_to?(:read_other_parameter_value)
|
56
|
+
read_date_parameter_value(name, values_from_param)
|
57
|
+
else
|
58
|
+
klass.new(*values)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def execute_callstack_for_multiparameter_attributes_with_timeliness(callstack)
|
64
|
+
errors = []
|
65
|
+
callstack.each do |name, values_with_empty_parameters|
|
66
|
+
begin
|
67
|
+
send(name + "=", read_value_from_parameter(name, values_with_empty_parameters))
|
68
|
+
rescue => ex
|
69
|
+
values = values_with_empty_parameters.is_a?(Hash) ? values_with_empty_parameters.values : values_with_empty_parameters
|
70
|
+
errors << ActiveRecord::AttributeAssignmentError.new("error on assignment #{values.inspect} to #{name}", ex, name)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
unless errors.empty?
|
74
|
+
raise ActiveRecord::MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|