activemodel 3.0.20 → 3.1.0.beta1
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.
- data/CHANGELOG +17 -73
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/lib/active_model.rb +2 -2
- data/lib/active_model/attribute_methods.rb +46 -53
- data/lib/active_model/callbacks.rb +2 -5
- data/lib/active_model/conversion.rb +0 -2
- data/lib/active_model/dirty.rb +3 -4
- data/lib/active_model/errors.rb +55 -56
- data/lib/active_model/lint.rb +2 -2
- data/lib/active_model/mass_assignment_security.rb +96 -47
- data/lib/active_model/naming.rb +55 -13
- data/lib/active_model/observer_array.rb +104 -0
- data/lib/active_model/observing.rb +53 -18
- data/lib/active_model/secure_password.rb +67 -0
- data/lib/active_model/serialization.rb +4 -11
- data/lib/active_model/serializers/json.rb +18 -18
- data/lib/active_model/serializers/xml.rb +26 -5
- data/lib/active_model/translation.rb +4 -11
- data/lib/active_model/validations.rb +23 -23
- data/lib/active_model/validations/acceptance.rb +3 -5
- data/lib/active_model/validations/callbacks.rb +5 -19
- data/lib/active_model/validations/confirmation.rb +6 -5
- data/lib/active_model/validations/exclusion.rb +27 -3
- data/lib/active_model/validations/format.rb +38 -12
- data/lib/active_model/validations/inclusion.rb +30 -23
- data/lib/active_model/validations/length.rb +3 -1
- data/lib/active_model/validations/numericality.rb +4 -2
- data/lib/active_model/validations/presence.rb +3 -2
- data/lib/active_model/validations/validates.rb +23 -9
- data/lib/active_model/validations/with.rb +14 -2
- data/lib/active_model/validator.rb +16 -18
- data/lib/active_model/version.rb +3 -3
- metadata +71 -58
- checksums.yaml +0 -7
- data/lib/active_model/deprecated_error_methods.rb +0 -33
data/CHANGELOG
CHANGED
@@ -1,83 +1,27 @@
|
|
1
|
-
|
1
|
+
*Rails 3.1.0 (unreleased)*
|
2
2
|
|
3
|
-
*
|
3
|
+
* Add support for proc or lambda as an option for InclusionValidator,
|
4
|
+
ExclusionValidator, and FormatValidator [Prem Sichanugrist]
|
4
5
|
|
5
|
-
|
6
|
+
You can now supply Proc, lambda, or anything that respond to #call in those
|
7
|
+
validations, and it will be called with current record as an argument.
|
8
|
+
That given proc or lambda must returns an object which respond to #include? for
|
9
|
+
InclusionValidator and ExclusionValidator, and returns a regular expression
|
10
|
+
object for FormatValidator.
|
6
11
|
|
7
|
-
*
|
12
|
+
* Added ActiveModel::SecurePassword to encapsulate dead-simple password usage with BCrypt encryption and salting [DHH]
|
8
13
|
|
9
|
-
|
14
|
+
* ActiveModel::AttributeMethods allows attributes to be defined on demand [Alexander Uvarov]
|
10
15
|
|
11
|
-
* No changes.
|
12
16
|
|
13
|
-
|
17
|
+
*Rails 3.0.2 (unreleased)*
|
14
18
|
|
15
|
-
* No changes
|
16
|
-
|
17
|
-
## Rails 3.0.16 (Jul 26, 2012)
|
18
|
-
|
19
|
-
* No changes.
|
20
|
-
|
21
|
-
## Rails 3.0.14 (Jun 12, 2012)
|
22
|
-
|
23
|
-
* No changes.
|
24
|
-
|
25
|
-
*Rails 3.0.13 (May 31, 2012)*
|
26
|
-
|
27
|
-
* No changes.
|
28
|
-
|
29
|
-
*Rails 3.0.10 (August 16, 2011)*
|
30
|
-
|
31
|
-
*No changes.
|
32
|
-
|
33
|
-
|
34
|
-
*Rails 3.0.9 (June 16, 2011)*
|
35
|
-
|
36
|
-
*No changes.
|
37
|
-
|
38
|
-
|
39
|
-
*Rails 3.0.8 (June 7, 2011)*
|
40
|
-
|
41
|
-
*No changes.
|
42
|
-
|
43
|
-
|
44
|
-
*Rails 3.0.7 (April 18, 2011)*
|
45
|
-
|
46
|
-
*No changes.
|
47
|
-
|
48
|
-
|
49
|
-
*Rails 3.0.6 (April 5, 2011)
|
50
|
-
|
51
|
-
* Fix when database column name has some symbolic characters (e.g. Oracle CASE# VARCHAR2(20)) #5818 #6850 [Robert Pankowecki, Santiago Pastorino]
|
52
|
-
|
53
|
-
* Fix length validation for fixnums #6556 [Andriy Tyurnikov]
|
54
|
-
|
55
|
-
* Fix i18n key collision with namespaced models #6448 [yves.senn]
|
56
|
-
|
57
|
-
|
58
|
-
*Rails 3.0.5 (February 26, 2011)*
|
59
|
-
|
60
|
-
* No changes.
|
61
|
-
|
62
|
-
|
63
|
-
*Rails 3.0.4 (February 8, 2011)*
|
64
|
-
|
65
|
-
* No changes.
|
66
|
-
|
67
|
-
|
68
|
-
*Rails 3.0.3 (November 16, 2010)*
|
69
|
-
|
70
|
-
* No changes.
|
71
|
-
|
72
|
-
|
73
|
-
*Rails 3.0.2 (November 15, 2010)*
|
74
|
-
|
75
|
-
* No changes.
|
19
|
+
* No changes
|
76
20
|
|
77
21
|
|
78
22
|
*Rails 3.0.1 (October 15, 2010)*
|
79
23
|
|
80
|
-
* No
|
24
|
+
* No Changes, just a version bump.
|
81
25
|
|
82
26
|
|
83
27
|
*Rails 3.0.0 (August 29, 2010)*
|
@@ -103,10 +47,10 @@
|
|
103
47
|
It has a custom hook to define after_find that should really be in a
|
104
48
|
ActiveRecord::Observer subclass:
|
105
49
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
50
|
+
def add_observer!(klass)
|
51
|
+
klass.add_observer(self)
|
52
|
+
klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find)
|
53
|
+
end
|
110
54
|
|
111
55
|
* Change the ActiveModel::Base.include_root_in_json default to true for Rails 3 [DHH]
|
112
56
|
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -8,7 +8,7 @@ the Rails framework.
|
|
8
8
|
Prior to Rails 3.0, if a plugin or gem developer wanted to have an object
|
9
9
|
interact with Action Pack helpers, it was required to either copy chunks of
|
10
10
|
code from Rails, or monkey patch entire helpers to make them handle objects
|
11
|
-
that did not
|
11
|
+
that did not exactly conform to the Active Record interface. This would result
|
12
12
|
in code duplication and fragile applications that broke on upgrades.
|
13
13
|
|
14
14
|
Active Model solves this. You can include functionality from the following
|
@@ -41,7 +41,7 @@ modules:
|
|
41
41
|
define_model_callbacks :create
|
42
42
|
|
43
43
|
def create
|
44
|
-
|
44
|
+
run_callbacks :create do
|
45
45
|
# Your create action methods here
|
46
46
|
end
|
47
47
|
end
|
@@ -84,7 +84,7 @@ modules:
|
|
84
84
|
attr_reader :errors
|
85
85
|
|
86
86
|
def validate!
|
87
|
-
errors.add(:name, "can not be nil") if name
|
87
|
+
errors.add(:name, "can not be nil") if name.nil?
|
88
88
|
end
|
89
89
|
|
90
90
|
def ErrorsPerson.human_attribute_name(attr, options = {})
|
@@ -94,10 +94,10 @@ modules:
|
|
94
94
|
end
|
95
95
|
|
96
96
|
person.errors.full_messages
|
97
|
-
# => ["Name
|
97
|
+
# => ["Name can not be nil"]
|
98
98
|
|
99
99
|
person.errors.full_messages
|
100
|
-
# => ["Name
|
100
|
+
# => ["Name can not be nil"]
|
101
101
|
|
102
102
|
{Learn more}[link:classes/ActiveModel/Errors.html]
|
103
103
|
|
data/lib/active_model.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2004-
|
2
|
+
# Copyright (c) 2004-2011 David Heinemeier Hansson
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -33,7 +33,6 @@ module ActiveModel
|
|
33
33
|
autoload :BlockValidator, 'active_model/validator'
|
34
34
|
autoload :Callbacks
|
35
35
|
autoload :Conversion
|
36
|
-
autoload :DeprecatedErrorMethods
|
37
36
|
autoload :Dirty
|
38
37
|
autoload :EachValidator, 'active_model/validator'
|
39
38
|
autoload :Errors
|
@@ -43,6 +42,7 @@ module ActiveModel
|
|
43
42
|
autoload :Naming
|
44
43
|
autoload :Observer, 'active_model/observing'
|
45
44
|
autoload :Observing
|
45
|
+
autoload :SecurePassword
|
46
46
|
autoload :Serialization
|
47
47
|
autoload :TestCase
|
48
48
|
autoload :Translation
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'active_support/core_ext/hash/keys'
|
2
|
-
require 'active_support/core_ext/class/
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
3
|
|
4
4
|
module ActiveModel
|
5
5
|
class MissingAttributeError < NoMethodError
|
@@ -56,7 +56,12 @@ module ActiveModel
|
|
56
56
|
module AttributeMethods
|
57
57
|
extend ActiveSupport::Concern
|
58
58
|
|
59
|
-
COMPILABLE_REGEXP =
|
59
|
+
COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
|
60
|
+
|
61
|
+
included do
|
62
|
+
class_attribute :attribute_method_matchers, :instance_writer => false
|
63
|
+
self.attribute_method_matchers = []
|
64
|
+
end
|
60
65
|
|
61
66
|
module ClassMethods
|
62
67
|
# Defines an "attribute" method (like +inheritance_column+ or +table_name+).
|
@@ -95,7 +100,7 @@ module ActiveModel
|
|
95
100
|
def define_attr_method(name, value=nil, &block)
|
96
101
|
sing = singleton_class
|
97
102
|
sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
|
98
|
-
if method_defined?(
|
103
|
+
if method_defined?('original_#{name}')
|
99
104
|
undef :'original_#{name}'
|
100
105
|
end
|
101
106
|
alias_method :'original_#{name}', :'#{name}'
|
@@ -151,7 +156,7 @@ module ActiveModel
|
|
151
156
|
# person.clear_name
|
152
157
|
# person.name # => nil
|
153
158
|
def attribute_method_prefix(*prefixes)
|
154
|
-
attribute_method_matchers
|
159
|
+
self.attribute_method_matchers += prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix }
|
155
160
|
undefine_attribute_methods
|
156
161
|
end
|
157
162
|
|
@@ -188,7 +193,7 @@ module ActiveModel
|
|
188
193
|
# person.name # => "Bob"
|
189
194
|
# person.name_short? # => true
|
190
195
|
def attribute_method_suffix(*suffixes)
|
191
|
-
attribute_method_matchers
|
196
|
+
self.attribute_method_matchers += suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix }
|
192
197
|
undefine_attribute_methods
|
193
198
|
end
|
194
199
|
|
@@ -226,7 +231,7 @@ module ActiveModel
|
|
226
231
|
# person.reset_name_to_default!
|
227
232
|
# person.name # => 'Gemma'
|
228
233
|
def attribute_method_affix(*affixes)
|
229
|
-
attribute_method_matchers
|
234
|
+
self.attribute_method_matchers += affixes.map { |affix| AttributeMethodMatcher.new :prefix => affix[:prefix], :suffix => affix[:suffix] }
|
230
235
|
undefine_attribute_methods
|
231
236
|
end
|
232
237
|
|
@@ -249,7 +254,7 @@ module ActiveModel
|
|
249
254
|
end
|
250
255
|
end
|
251
256
|
|
252
|
-
# Declares
|
257
|
+
# Declares the attributes that should be prefixed and suffixed by
|
253
258
|
# ActiveModel::AttributeMethods.
|
254
259
|
#
|
255
260
|
# To use, pass in an array of attribute names (as strings or symbols),
|
@@ -274,41 +279,41 @@ module ActiveModel
|
|
274
279
|
# end
|
275
280
|
# end
|
276
281
|
def define_attribute_methods(attr_names)
|
277
|
-
|
278
|
-
|
279
|
-
attribute_method_matchers.each do |matcher|
|
280
|
-
unless instance_method_already_implemented?(matcher.method_name(attr_name))
|
281
|
-
generate_method = "define_method_#{matcher.prefix}attribute#{matcher.suffix}"
|
282
|
+
attr_names.each { |attr_name| define_attribute_method(attr_name) }
|
283
|
+
end
|
282
284
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
285
|
+
def define_attribute_method(attr_name)
|
286
|
+
attribute_method_matchers.each do |matcher|
|
287
|
+
unless instance_method_already_implemented?(matcher.method_name(attr_name))
|
288
|
+
generate_method = "define_method_#{matcher.prefix}attribute#{matcher.suffix}"
|
287
289
|
|
290
|
+
if respond_to?(generate_method)
|
291
|
+
send(generate_method, attr_name)
|
292
|
+
else
|
293
|
+
method_name = matcher.method_name(attr_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
|
288
302
|
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
289
|
-
|
290
|
-
|
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)
|
291
311
|
end
|
292
312
|
RUBY
|
293
|
-
|
294
|
-
if method_name.to_s =~ COMPILABLE_REGEXP
|
295
|
-
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
296
|
-
def #{method_name}(*args)
|
297
|
-
send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
|
298
|
-
end
|
299
|
-
RUBY
|
300
|
-
else
|
301
|
-
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
302
|
-
define_method('#{method_name}') do |*args|
|
303
|
-
send('#{matcher.method_missing_target}', '#{attr_name}', *args)
|
304
|
-
end
|
305
|
-
RUBY
|
306
|
-
end
|
307
313
|
end
|
308
314
|
end
|
309
315
|
end
|
310
316
|
end
|
311
|
-
@attribute_methods_generated = true
|
312
317
|
end
|
313
318
|
|
314
319
|
# Removes all the previously dynamically defined methods from the class
|
@@ -316,7 +321,6 @@ module ActiveModel
|
|
316
321
|
generated_attribute_methods.module_eval do
|
317
322
|
instance_methods.each { |m| undef_method(m) }
|
318
323
|
end
|
319
|
-
@attribute_methods_generated = nil
|
320
324
|
end
|
321
325
|
|
322
326
|
# Returns true if the attribute methods defined have been generated.
|
@@ -328,11 +332,6 @@ module ActiveModel
|
|
328
332
|
end
|
329
333
|
end
|
330
334
|
|
331
|
-
# Returns true if the attribute methods defined have been generated.
|
332
|
-
def attribute_methods_generated?
|
333
|
-
@attribute_methods_generated ||= nil
|
334
|
-
end
|
335
|
-
|
336
335
|
protected
|
337
336
|
def instance_method_already_implemented?(method_name)
|
338
337
|
method_defined?(method_name)
|
@@ -340,7 +339,7 @@ module ActiveModel
|
|
340
339
|
|
341
340
|
private
|
342
341
|
class AttributeMethodMatcher
|
343
|
-
attr_reader :prefix, :suffix
|
342
|
+
attr_reader :prefix, :suffix, :method_missing_target
|
344
343
|
|
345
344
|
AttributeMethodMatch = Struct.new(:target, :attr_name)
|
346
345
|
|
@@ -348,28 +347,22 @@ module ActiveModel
|
|
348
347
|
options.symbolize_keys!
|
349
348
|
@prefix, @suffix = options[:prefix] || '', options[:suffix] || ''
|
350
349
|
@regex = /^(#{Regexp.escape(@prefix)})(.+?)(#{Regexp.escape(@suffix)})$/
|
350
|
+
@method_missing_target = "#{@prefix}attribute#{@suffix}"
|
351
|
+
@method_name = "#{prefix}%s#{suffix}"
|
351
352
|
end
|
352
353
|
|
353
354
|
def match(method_name)
|
354
|
-
if
|
355
|
-
AttributeMethodMatch.new(method_missing_target,
|
355
|
+
if @regex =~ method_name
|
356
|
+
AttributeMethodMatch.new(method_missing_target, $2)
|
356
357
|
else
|
357
358
|
nil
|
358
359
|
end
|
359
360
|
end
|
360
361
|
|
361
362
|
def method_name(attr_name)
|
362
|
-
|
363
|
-
end
|
364
|
-
|
365
|
-
def method_missing_target
|
366
|
-
:"#{prefix}attribute#{suffix}"
|
363
|
+
@method_name % attr_name
|
367
364
|
end
|
368
365
|
end
|
369
|
-
|
370
|
-
def attribute_method_matchers #:nodoc:
|
371
|
-
read_inheritable_attribute(:attribute_method_matchers) || write_inheritable_attribute(:attribute_method_matchers, [])
|
372
|
-
end
|
373
366
|
end
|
374
367
|
|
375
368
|
# Allows access to the object attributes, which are held in the
|
@@ -418,7 +411,7 @@ module ActiveModel
|
|
418
411
|
# Returns a struct representing the matching attribute method.
|
419
412
|
# The struct's attributes are prefix, base and suffix.
|
420
413
|
def match_attribute_method?(method_name)
|
421
|
-
self.class.
|
414
|
+
self.class.attribute_method_matchers.each do |method|
|
422
415
|
if (match = method.match(method_name)) && attribute_method?(match.attr_name)
|
423
416
|
return match
|
424
417
|
end
|
@@ -429,7 +422,7 @@ module ActiveModel
|
|
429
422
|
# prevent method_missing from calling private methods with #send
|
430
423
|
def guard_private_attribute_method!(method_name, args)
|
431
424
|
if self.class.private_method_defined?(method_name)
|
432
|
-
raise NoMethodError.new("Attempt to call private method", method_name, args)
|
425
|
+
raise NoMethodError.new("Attempt to call private method `#{method_name}'", method_name, args)
|
433
426
|
end
|
434
427
|
end
|
435
428
|
|
@@ -24,14 +24,11 @@ module ActiveModel
|
|
24
24
|
# you want callbacks on in a block so that the callbacks get a chance to fire:
|
25
25
|
#
|
26
26
|
# def create
|
27
|
-
#
|
27
|
+
# run_callbacks :create do
|
28
28
|
# # Your create action methods here
|
29
29
|
# end
|
30
30
|
# end
|
31
31
|
#
|
32
|
-
# The _run_<method_name>_callbacks methods are dynamically created when you extend
|
33
|
-
# the <tt>ActiveModel::Callbacks</tt> module.
|
34
|
-
#
|
35
32
|
# Then in your class, you can use the +before_create+, +after_create+ and +around_create+
|
36
33
|
# methods, just as you would in an Active Record module.
|
37
34
|
#
|
@@ -102,7 +99,7 @@ module ActiveModel
|
|
102
99
|
define_callbacks(callback, options)
|
103
100
|
|
104
101
|
types.each do |type|
|
105
|
-
send(
|
102
|
+
send("_define_#{type}_model_callback", self, callback)
|
106
103
|
end
|
107
104
|
end
|
108
105
|
end
|
data/lib/active_model/dirty.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'active_model/attribute_methods'
|
2
|
-
require 'active_support/concern'
|
3
2
|
require 'active_support/hash_with_indifferent_access'
|
4
3
|
require 'active_support/core_ext/object/duplicable'
|
5
4
|
|
@@ -9,7 +8,7 @@ module ActiveModel
|
|
9
8
|
# Provides a way to track changes in your object in the same way as
|
10
9
|
# Active Record does.
|
11
10
|
#
|
12
|
-
# The requirements
|
11
|
+
# The requirements for implementing ActiveModel::Dirty are:
|
13
12
|
#
|
14
13
|
# * <tt>include ActiveModel::Dirty</tt> in your object
|
15
14
|
# * Call <tt>define_attribute_methods</tt> passing each method you want to
|
@@ -94,7 +93,7 @@ module ActiveModel
|
|
94
93
|
attribute_method_affix :prefix => 'reset_', :suffix => '!'
|
95
94
|
end
|
96
95
|
|
97
|
-
#
|
96
|
+
# Returns true if any attribute have unsaved changes, false otherwise.
|
98
97
|
# person.changed? # => false
|
99
98
|
# person.name = 'bob'
|
100
99
|
# person.changed? # => true
|
@@ -115,7 +114,7 @@ module ActiveModel
|
|
115
114
|
# person.name = 'bob'
|
116
115
|
# person.changes # => { 'name' => ['bill', 'bob'] }
|
117
116
|
def changes
|
118
|
-
changed.
|
117
|
+
HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
|
119
118
|
end
|
120
119
|
|
121
120
|
# Map of attributes that were changed when the model was saved.
|