activemodel 3.1.12 → 3.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +81 -36
- data/README.rdoc +1 -1
- data/lib/active_model/attribute_methods.rb +123 -104
- data/lib/active_model/callbacks.rb +2 -2
- data/lib/active_model/conversion.rb +26 -2
- data/lib/active_model/dirty.rb +3 -3
- data/lib/active_model/errors.rb +63 -51
- data/lib/active_model/lint.rb +12 -3
- data/lib/active_model/mass_assignment_security.rb +27 -8
- data/lib/active_model/mass_assignment_security/permission_set.rb +5 -5
- data/lib/active_model/mass_assignment_security/sanitizer.rb +42 -6
- data/lib/active_model/naming.rb +18 -10
- data/lib/active_model/observer_array.rb +3 -3
- data/lib/active_model/observing.rb +1 -2
- data/lib/active_model/secure_password.rb +2 -2
- data/lib/active_model/serialization.rb +61 -10
- data/lib/active_model/serializers/json.rb +20 -14
- data/lib/active_model/serializers/xml.rb +55 -31
- data/lib/active_model/translation.rb +15 -3
- data/lib/active_model/validations.rb +1 -1
- data/lib/active_model/validations/acceptance.rb +3 -1
- data/lib/active_model/validations/confirmation.rb +3 -1
- data/lib/active_model/validations/exclusion.rb +5 -3
- data/lib/active_model/validations/format.rb +4 -2
- data/lib/active_model/validations/inclusion.rb +5 -3
- data/lib/active_model/validations/length.rb +22 -10
- data/lib/active_model/validations/numericality.rb +4 -2
- data/lib/active_model/validations/presence.rb +5 -3
- data/lib/active_model/validations/validates.rb +15 -3
- data/lib/active_model/validations/with.rb +4 -2
- data/lib/active_model/version.rb +3 -3
- metadata +21 -28
- checksums.yaml +0 -7
data/CHANGELOG.md
CHANGED
@@ -1,71 +1,116 @@
|
|
1
|
-
## Rails 3.
|
1
|
+
## Rails 3.2.0 (unreleased) ##
|
2
2
|
|
3
|
-
*
|
4
|
-
|
3
|
+
* Deprecated `define_attr_method` in `ActiveModel::AttributeMethods`, because this only existed to
|
4
|
+
support methods like `set_table_name` in Active Record, which are themselves being deprecated.
|
5
5
|
|
6
|
-
*
|
6
|
+
*Jon Leighton*
|
7
7
|
|
8
|
-
|
8
|
+
* Add ActiveModel::Errors#added? to check if a specific error has been added *Martin Svalin*
|
9
9
|
|
10
|
-
*
|
10
|
+
* Add ability to define strict validation(with :strict => true option) that always raises exception when fails *Bogdan Gusiev*
|
11
|
+
|
12
|
+
* Deprecate "Model.model_name.partial_path" in favor of "model.to_partial_path" *Grant Hutchins, Peter Jaros*
|
11
13
|
|
12
|
-
|
14
|
+
* Provide mass_assignment_sanitizer as an easy API to replace the sanitizer behavior. Also support both :logger (default) and :strict sanitizer behavior *Bogdan Gusiev*
|
15
|
+
|
16
|
+
## Rails 3.1.0 (August 30, 2011) ##
|
17
|
+
|
18
|
+
* Alternate I18n namespace lookup is no longer supported.
|
19
|
+
Instead of "activerecord.models.admins.post", do "activerecord.models.admins/post" instead *José Valim*
|
13
20
|
|
14
|
-
*
|
21
|
+
* attr_accessible and friends now accepts :as as option to specify a role *Josh Kalderimis*
|
22
|
+
|
23
|
+
* Add support for proc or lambda as an option for InclusionValidator,
|
24
|
+
ExclusionValidator, and FormatValidator *Prem Sichanugrist*
|
25
|
+
|
26
|
+
You can now supply Proc, lambda, or anything that respond to #call in those
|
27
|
+
validations, and it will be called with current record as an argument.
|
28
|
+
That given proc or lambda must returns an object which respond to #include? for
|
29
|
+
InclusionValidator and ExclusionValidator, and returns a regular expression
|
30
|
+
object for FormatValidator.
|
15
31
|
|
16
|
-
|
32
|
+
* Added ActiveModel::SecurePassword to encapsulate dead-simple password usage with BCrypt encryption and salting *DHH*
|
17
33
|
|
18
|
-
|
34
|
+
* ActiveModel::AttributeMethods allows attributes to be defined on demand *Alexander Uvarov*
|
19
35
|
|
20
|
-
|
36
|
+
* Add support for selectively enabling/disabling observers *Myron Marston*
|
21
37
|
|
22
|
-
*Carlos Antonio da Silva*
|
23
38
|
|
24
|
-
## Rails 3.
|
39
|
+
## Rails 3.0.7 (April 18, 2011) ##
|
25
40
|
|
26
41
|
* No changes.
|
27
42
|
|
28
|
-
|
43
|
+
|
44
|
+
* Rails 3.0.6 (April 5, 2011)
|
45
|
+
|
46
|
+
* Fix when database column name has some symbolic characters (e.g. Oracle CASE# VARCHAR2(20)) #5818 #6850 *Robert Pankowecki, Santiago Pastorino*
|
47
|
+
|
48
|
+
* Fix length validation for fixnums #6556 *Andriy Tyurnikov*
|
49
|
+
|
50
|
+
* Fix i18n key collision with namespaced models #6448 *yves.senn*
|
51
|
+
|
52
|
+
|
53
|
+
## Rails 3.0.5 (February 26, 2011) ##
|
29
54
|
|
30
55
|
* No changes.
|
31
56
|
|
32
|
-
|
57
|
+
|
58
|
+
## Rails 3.0.4 (February 8, 2011) ##
|
33
59
|
|
34
60
|
* No changes.
|
35
61
|
|
36
|
-
|
62
|
+
|
63
|
+
## Rails 3.0.3 (November 16, 2010) ##
|
37
64
|
|
38
65
|
* No changes.
|
39
66
|
|
40
|
-
## Rails 3.1.1 (October 7, 2011) ##
|
41
67
|
|
42
|
-
|
43
|
-
You must add the gem explicitly to your Gemfile if you want use ActiveModel::SecurePassword:
|
68
|
+
## Rails 3.0.2 (November 15, 2010) ##
|
44
69
|
|
45
|
-
|
70
|
+
* No changes
|
46
71
|
|
47
|
-
See GH #2687. *Guillermo Iguaran*
|
48
72
|
|
49
|
-
## Rails 3.1
|
73
|
+
## Rails 3.0.1 (October 15, 2010) ##
|
50
74
|
|
51
|
-
*
|
52
|
-
Instead of "activerecord.models.admins.post", do "activerecord.models.admins/post" instead *José Valim*
|
75
|
+
* No Changes, just a version bump.
|
53
76
|
|
54
|
-
* attr_accessible and friends now accepts :as as option to specify a role *Josh Kalderimis*
|
55
77
|
|
56
|
-
|
57
|
-
ExclusionValidator, and FormatValidator *Prem Sichanugrist*
|
78
|
+
## Rails 3.0.0 (August 29, 2010) ##
|
58
79
|
|
59
|
-
|
60
|
-
validations, and it will be called with current record as an argument.
|
61
|
-
That given proc or lambda must returns an object which respond to #include? for
|
62
|
-
InclusionValidator and ExclusionValidator, and returns a regular expression
|
63
|
-
object for FormatValidator.
|
80
|
+
* Added ActiveModel::MassAssignmentSecurity *Eric Chapweske, Josh Kalderimis*
|
64
81
|
|
65
|
-
*
|
82
|
+
* JSON supports a custom root option: to_json(:root => 'custom') #4515 *Jatinder Singh*
|
66
83
|
|
67
|
-
*
|
84
|
+
* #new_record? and #destroyed? were removed from ActiveModel::Lint. Use
|
85
|
+
persisted? instead. A model is persisted if it's not a new_record? and it was
|
86
|
+
not destroyed? *MG*
|
68
87
|
|
69
|
-
*
|
88
|
+
* Added validations reflection in ActiveModel::Validations *JV*
|
89
|
+
|
90
|
+
Model.validators
|
91
|
+
Model.validators_on(:field)
|
92
|
+
|
93
|
+
* #to_key was added to ActiveModel::Lint so we can generate DOM IDs for
|
94
|
+
AMo objects with composite keys *MG*
|
95
|
+
|
96
|
+
* ActiveModel::Observer#add_observer!
|
97
|
+
|
98
|
+
It has a custom hook to define after_find that should really be in a
|
99
|
+
ActiveRecord::Observer subclass:
|
100
|
+
|
101
|
+
def add_observer!(klass)
|
102
|
+
klass.add_observer(self)
|
103
|
+
klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find)
|
104
|
+
end
|
105
|
+
|
106
|
+
* Change the ActiveModel::Base.include_root_in_json default to true for Rails 3 *DHH*
|
107
|
+
|
108
|
+
* Add validates_format_of :without => /regexp/ option. #430 *Elliot Winkler, Peer Allan*
|
109
|
+
|
110
|
+
Example :
|
111
|
+
|
112
|
+
validates_format_of :subdomain, :without => /www|admin|mail/
|
113
|
+
|
114
|
+
* Introduce validates_with to encapsulate attribute validations in a class. #2630 *Jeff Dean*
|
70
115
|
|
71
|
-
|
116
|
+
* Extracted from Active Record and Active Resource.
|
data/README.rdoc
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/hash/keys'
|
2
2
|
require 'active_support/core_ext/class/attribute'
|
3
|
+
require 'active_support/deprecation'
|
3
4
|
|
4
5
|
module ActiveModel
|
5
6
|
class MissingAttributeError < NoMethodError
|
@@ -56,54 +57,38 @@ module ActiveModel
|
|
56
57
|
module AttributeMethods
|
57
58
|
extend ActiveSupport::Concern
|
58
59
|
|
59
|
-
|
60
|
+
NAME_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
|
61
|
+
CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
|
60
62
|
|
61
63
|
included do
|
62
64
|
class_attribute :attribute_method_matchers, :instance_writer => false
|
63
|
-
self.attribute_method_matchers = []
|
65
|
+
self.attribute_method_matchers = [ClassMethods::AttributeMethodMatcher.new]
|
64
66
|
end
|
65
67
|
|
66
68
|
module ClassMethods
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
#
|
79
|
-
# class Person
|
80
|
-
#
|
81
|
-
# include ActiveModel::AttributeMethods
|
82
|
-
#
|
83
|
-
# cattr_accessor :primary_key
|
84
|
-
# cattr_accessor :inheritance_column
|
85
|
-
#
|
86
|
-
# define_attr_method :primary_key, "sysid"
|
87
|
-
# define_attr_method( :inheritance_column ) do
|
88
|
-
# original_inheritance_column + "_id"
|
89
|
-
# end
|
90
|
-
#
|
91
|
-
# end
|
92
|
-
#
|
93
|
-
# Provides you with:
|
94
|
-
#
|
95
|
-
# Person.primary_key
|
96
|
-
# # => "sysid"
|
97
|
-
# Person.inheritance_column = 'address'
|
98
|
-
# Person.inheritance_column
|
99
|
-
# # => 'address_id'
|
100
|
-
def define_attr_method(name, value=nil, &block)
|
69
|
+
def define_attr_method(name, value=nil, deprecation_warning = true, &block) #:nodoc:
|
70
|
+
# This deprecation_warning param is for internal use so that we can silence
|
71
|
+
# the warning from Active Record, because we are implementing more specific
|
72
|
+
# messages there instead.
|
73
|
+
#
|
74
|
+
# It doesn't apply to the original_#{name} method as we want to warn if
|
75
|
+
# people are calling that regardless.
|
76
|
+
if deprecation_warning
|
77
|
+
ActiveSupport::Deprecation.warn("define_attr_method is deprecated and will be removed without replacement.")
|
78
|
+
end
|
79
|
+
|
101
80
|
sing = singleton_class
|
102
81
|
sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
|
103
|
-
|
104
|
-
|
82
|
+
remove_possible_method :'original_#{name}'
|
83
|
+
remove_possible_method :'_original_#{name}'
|
84
|
+
alias_method :'_original_#{name}', :'#{name}'
|
85
|
+
define_method :'original_#{name}' do
|
86
|
+
ActiveSupport::Deprecation.warn(
|
87
|
+
"This method is generated by ActiveModel::AttributeMethods::ClassMethods#define_attr_method, " \
|
88
|
+
"which is deprecated and will be removed."
|
89
|
+
)
|
90
|
+
send(:'_original_#{name}')
|
105
91
|
end
|
106
|
-
alias_method :'original_#{name}', :'#{name}'
|
107
92
|
eorb
|
108
93
|
if block_given?
|
109
94
|
sing.send :define_method, name, &block
|
@@ -111,7 +96,7 @@ module ActiveModel
|
|
111
96
|
# If we can compile the method name, do it. Otherwise use define_method.
|
112
97
|
# This is an important *optimization*, please don't change it. define_method
|
113
98
|
# has slower dispatch and consumes more memory.
|
114
|
-
if name =~
|
99
|
+
if name =~ NAME_COMPILABLE_REGEXP
|
115
100
|
sing.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
116
101
|
def #{name}; #{value.nil? ? 'nil' : value.to_s.inspect}; end
|
117
102
|
RUBY
|
@@ -239,18 +224,7 @@ module ActiveModel
|
|
239
224
|
attribute_method_matchers.each do |matcher|
|
240
225
|
matcher_new = matcher.method_name(new_name).to_s
|
241
226
|
matcher_old = matcher.method_name(old_name).to_s
|
242
|
-
|
243
|
-
if matcher_new =~ COMPILABLE_REGEXP && matcher_old =~ COMPILABLE_REGEXP
|
244
|
-
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
245
|
-
def #{matcher_new}(*args)
|
246
|
-
send(:#{matcher_old}, *args)
|
247
|
-
end
|
248
|
-
RUBY
|
249
|
-
else
|
250
|
-
define_method(matcher_new) do |*args|
|
251
|
-
send(matcher_old, *args)
|
252
|
-
end
|
253
|
-
end
|
227
|
+
define_optimized_call self, matcher_new, matcher_old
|
254
228
|
end
|
255
229
|
end
|
256
230
|
|
@@ -284,36 +258,19 @@ module ActiveModel
|
|
284
258
|
|
285
259
|
def define_attribute_method(attr_name)
|
286
260
|
attribute_method_matchers.each do |matcher|
|
287
|
-
|
288
|
-
|
261
|
+
method_name = matcher.method_name(attr_name)
|
262
|
+
|
263
|
+
unless instance_method_already_implemented?(method_name)
|
264
|
+
generate_method = "define_method_#{matcher.method_missing_target}"
|
289
265
|
|
290
|
-
if respond_to?(generate_method
|
266
|
+
if respond_to?(generate_method)
|
291
267
|
send(generate_method, attr_name)
|
292
268
|
else
|
293
|
-
method_name
|
294
|
-
|
295
|
-
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
296
|
-
if method_defined?('#{method_name}')
|
297
|
-
undef :'#{method_name}'
|
298
|
-
end
|
299
|
-
RUBY
|
300
|
-
|
301
|
-
if method_name.to_s =~ COMPILABLE_REGEXP
|
302
|
-
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
303
|
-
def #{method_name}(*args)
|
304
|
-
send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
|
305
|
-
end
|
306
|
-
RUBY
|
307
|
-
else
|
308
|
-
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
309
|
-
define_method('#{method_name}') do |*args|
|
310
|
-
send('#{matcher.method_missing_target}', '#{attr_name}', *args)
|
311
|
-
end
|
312
|
-
RUBY
|
313
|
-
end
|
269
|
+
define_optimized_call generated_attribute_methods, method_name, matcher.method_missing_target, attr_name.to_s
|
314
270
|
end
|
315
271
|
end
|
316
272
|
end
|
273
|
+
attribute_method_matchers_cache.clear
|
317
274
|
end
|
318
275
|
|
319
276
|
# Removes all the previously dynamically defined methods from the class
|
@@ -321,6 +278,7 @@ module ActiveModel
|
|
321
278
|
generated_attribute_methods.module_eval do
|
322
279
|
instance_methods.each { |m| undef_method(m) }
|
323
280
|
end
|
281
|
+
attribute_method_matchers_cache.clear
|
324
282
|
end
|
325
283
|
|
326
284
|
# Returns true if the attribute methods defined have been generated.
|
@@ -334,26 +292,87 @@ module ActiveModel
|
|
334
292
|
|
335
293
|
protected
|
336
294
|
def instance_method_already_implemented?(method_name)
|
337
|
-
method_defined?(method_name)
|
295
|
+
generated_attribute_methods.method_defined?(method_name)
|
338
296
|
end
|
339
297
|
|
340
298
|
private
|
299
|
+
# The methods +method_missing+ and +respond_to?+ of this module are
|
300
|
+
# invoked often in a typical rails, both of which invoke the method
|
301
|
+
# +match_attribute_method?+. The latter method iterates through an
|
302
|
+
# array doing regular expression matches, which results in a lot of
|
303
|
+
# object creations. Most of the times it returns a +nil+ match. As the
|
304
|
+
# match result is always the same given a +method_name+, this cache is
|
305
|
+
# used to alleviate the GC, which ultimately also speeds up the app
|
306
|
+
# significantly (in our case our test suite finishes 10% faster with
|
307
|
+
# this cache).
|
308
|
+
def attribute_method_matchers_cache #:nodoc:
|
309
|
+
@attribute_method_matchers_cache ||= {}
|
310
|
+
end
|
311
|
+
|
312
|
+
def attribute_method_matcher(method_name) #:nodoc:
|
313
|
+
if attribute_method_matchers_cache.key?(method_name)
|
314
|
+
attribute_method_matchers_cache[method_name]
|
315
|
+
else
|
316
|
+
# Must try to match prefixes/suffixes first, or else the matcher with no prefix/suffix
|
317
|
+
# will match every time.
|
318
|
+
matchers = attribute_method_matchers.partition(&:plain?).reverse.flatten(1)
|
319
|
+
match = nil
|
320
|
+
matchers.detect { |method| match = method.match(method_name) }
|
321
|
+
attribute_method_matchers_cache[method_name] = match
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# Define a method `name` in `mod` that dispatches to `send`
|
326
|
+
# using the given `extra` args. This fallbacks `define_method`
|
327
|
+
# and `send` if the given names cannot be compiled.
|
328
|
+
def define_optimized_call(mod, name, send, *extra) #:nodoc:
|
329
|
+
if name =~ NAME_COMPILABLE_REGEXP
|
330
|
+
defn = "def #{name}(*args)"
|
331
|
+
else
|
332
|
+
defn = "define_method(:'#{name}') do |*args|"
|
333
|
+
end
|
334
|
+
|
335
|
+
extra = (extra.map(&:inspect) << "*args").join(", ")
|
336
|
+
|
337
|
+
if send =~ CALL_COMPILABLE_REGEXP
|
338
|
+
target = "#{send}(#{extra})"
|
339
|
+
else
|
340
|
+
target = "send(:'#{send}', #{extra})"
|
341
|
+
end
|
342
|
+
|
343
|
+
mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
344
|
+
#{defn}
|
345
|
+
#{target}
|
346
|
+
end
|
347
|
+
RUBY
|
348
|
+
end
|
349
|
+
|
341
350
|
class AttributeMethodMatcher
|
342
351
|
attr_reader :prefix, :suffix, :method_missing_target
|
343
352
|
|
344
|
-
AttributeMethodMatch = Struct.new(:target, :attr_name)
|
353
|
+
AttributeMethodMatch = Struct.new(:target, :attr_name, :method_name)
|
345
354
|
|
346
355
|
def initialize(options = {})
|
347
356
|
options.symbolize_keys!
|
357
|
+
|
358
|
+
if options[:prefix] == '' || options[:suffix] == ''
|
359
|
+
ActiveSupport::Deprecation.warn(
|
360
|
+
"Specifying an empty prefix/suffix for an attribute method is no longer " \
|
361
|
+
"necessary. If the un-prefixed/suffixed version of the method has not been " \
|
362
|
+
"defined when `define_attribute_methods` is called, it will be defined " \
|
363
|
+
"automatically."
|
364
|
+
)
|
365
|
+
end
|
366
|
+
|
348
367
|
@prefix, @suffix = options[:prefix] || '', options[:suffix] || ''
|
349
|
-
@regex =
|
368
|
+
@regex = /^(#{Regexp.escape(@prefix)})(.+?)(#{Regexp.escape(@suffix)})$/
|
350
369
|
@method_missing_target = "#{@prefix}attribute#{@suffix}"
|
351
370
|
@method_name = "#{prefix}%s#{suffix}"
|
352
371
|
end
|
353
372
|
|
354
373
|
def match(method_name)
|
355
374
|
if @regex =~ method_name
|
356
|
-
AttributeMethodMatch.new(method_missing_target, $2)
|
375
|
+
AttributeMethodMatch.new(method_missing_target, $2, method_name)
|
357
376
|
else
|
358
377
|
nil
|
359
378
|
end
|
@@ -362,6 +381,10 @@ module ActiveModel
|
|
362
381
|
def method_name(attr_name)
|
363
382
|
@method_name % attr_name
|
364
383
|
end
|
384
|
+
|
385
|
+
def plain?
|
386
|
+
prefix.empty? && suffix.empty?
|
387
|
+
end
|
365
388
|
end
|
366
389
|
end
|
367
390
|
|
@@ -376,13 +399,21 @@ module ActiveModel
|
|
376
399
|
# It's also possible to instantiate related objects, so a Client class
|
377
400
|
# belonging to the clients table with a +master_id+ foreign key can
|
378
401
|
# instantiate master through Client#master.
|
379
|
-
def method_missing(
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
402
|
+
def method_missing(method, *args, &block)
|
403
|
+
if respond_to_without_attributes?(method, true)
|
404
|
+
super
|
405
|
+
else
|
406
|
+
match = match_attribute_method?(method.to_s)
|
407
|
+
match ? attribute_missing(match, *args, &block) : super
|
384
408
|
end
|
385
|
-
|
409
|
+
end
|
410
|
+
|
411
|
+
# attribute_missing is like method_missing, but for attributes. When method_missing is
|
412
|
+
# called we check to see if there is a matching attribute method. If so, we call
|
413
|
+
# attribute_missing to dispatch the attribute. This method can be overloaded to
|
414
|
+
# customise the behaviour.
|
415
|
+
def attribute_missing(match, *args, &block)
|
416
|
+
__send__(match.target, match.attr_name, *args, &block)
|
386
417
|
end
|
387
418
|
|
388
419
|
# A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
|
@@ -391,15 +422,14 @@ module ActiveModel
|
|
391
422
|
alias :respond_to_without_attributes? :respond_to?
|
392
423
|
def respond_to?(method, include_private_methods = false)
|
393
424
|
if super
|
394
|
-
|
425
|
+
true
|
395
426
|
elsif !include_private_methods && super(method, true)
|
396
427
|
# If we're here then we haven't found among non-private methods
|
397
428
|
# but found among all methods. Which means that the given method is private.
|
398
|
-
|
399
|
-
|
400
|
-
|
429
|
+
false
|
430
|
+
else
|
431
|
+
!match_attribute_method?(method.to_s).nil?
|
401
432
|
end
|
402
|
-
super
|
403
433
|
end
|
404
434
|
|
405
435
|
protected
|
@@ -411,19 +441,8 @@ module ActiveModel
|
|
411
441
|
# Returns a struct representing the matching attribute method.
|
412
442
|
# The struct's attributes are prefix, base and suffix.
|
413
443
|
def match_attribute_method?(method_name)
|
414
|
-
self.class.
|
415
|
-
|
416
|
-
return match
|
417
|
-
end
|
418
|
-
end
|
419
|
-
nil
|
420
|
-
end
|
421
|
-
|
422
|
-
# prevent method_missing from calling private methods with #send
|
423
|
-
def guard_private_attribute_method!(method_name, args)
|
424
|
-
if self.class.private_method_defined?(method_name)
|
425
|
-
raise NoMethodError.new("Attempt to call private method `#{method_name}'", method_name, args)
|
426
|
-
end
|
444
|
+
match = self.class.send(:attribute_method_matcher, method_name)
|
445
|
+
match && attribute_method?(match.attr_name) ? match : nil
|
427
446
|
end
|
428
447
|
|
429
448
|
def missing_attribute(attr_name, stack)
|