activemodel 4.0.0.beta1 → 4.0.0.rc1
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 +4 -4
- data/CHANGELOG.md +72 -2
- data/README.rdoc +8 -8
- data/lib/active_model/attribute_methods.rb +32 -28
- data/lib/active_model/conversion.rb +1 -1
- data/lib/active_model/dirty.rb +1 -1
- data/lib/active_model/errors.rb +14 -2
- data/lib/active_model/secure_password.rb +22 -11
- data/lib/active_model/validations.rb +44 -4
- data/lib/active_model/validations/confirmation.rb +5 -1
- data/lib/active_model/version.rb +7 -6
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 250ef70b10d4ec2e30333cfffc80da63aed87895
|
4
|
+
data.tar.gz: 69c232cc5ed875faedbb29a0f0d6c1a01bcf5d19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0be6ba150a3151982443cf95e5c2a04da6af1b807282767e5ca44a4367830b070cbaa631dffaf3d65494a9e8cafe72f6ba19dcdb71d504c01009902a09865964
|
7
|
+
data.tar.gz: 836ccca90ace183c3e7944cbefb229a369db445f34fe68289d9af0444e29058f6834b9495b5554d95180c8777517977009eb94ad5de1d4880bdbc0125616bbaa
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,73 @@
|
|
1
|
+
## Rails 4.0.0 (unreleased) ##
|
2
|
+
|
3
|
+
* Add `ActiveModel::Errors#full_messages_for`, to return all the error messages
|
4
|
+
for a given attribute.
|
5
|
+
|
6
|
+
Example:
|
7
|
+
|
8
|
+
class Person
|
9
|
+
include ActiveModel::Validations
|
10
|
+
|
11
|
+
attr_reader :name, :email
|
12
|
+
validates_presence_of :name, :email
|
13
|
+
end
|
14
|
+
|
15
|
+
person = Person.new
|
16
|
+
person.valid? # => false
|
17
|
+
person.errors.full_messages_for(:name) # => ["Name can't be blank"]
|
18
|
+
|
19
|
+
*Volodymyr Shatsky*
|
20
|
+
|
21
|
+
* Added a method so that validations can be easily cleared on a model.
|
22
|
+
For example:
|
23
|
+
|
24
|
+
class Person
|
25
|
+
include ActiveModel::Validations
|
26
|
+
|
27
|
+
validates_uniqueness_of :first_name
|
28
|
+
validate :cannot_be_robot
|
29
|
+
|
30
|
+
def cannot_be_robot
|
31
|
+
errors.add(:base, 'A person cannot be a robot') if person_is_robot
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Now, if someone runs `Person.clear_validators!`, then the following occurs:
|
36
|
+
|
37
|
+
Person.validators # => []
|
38
|
+
Person._validate_callbacks.empty? # => true
|
39
|
+
|
40
|
+
*John Wang*
|
41
|
+
|
42
|
+
* `has_secure_password` does not fail the confirmation validation
|
43
|
+
when assigning empty String to `password` and `password_confirmation`.
|
44
|
+
Fixes #9535.
|
45
|
+
|
46
|
+
Example:
|
47
|
+
|
48
|
+
# Given User has_secure_password.
|
49
|
+
@user.password = ""
|
50
|
+
@user.password_confirmation = ""
|
51
|
+
@user.valid?(:update) # used to be false
|
52
|
+
|
53
|
+
*Yves Senn*
|
54
|
+
|
55
|
+
* `validates_confirmation_of` does not override writer methods for
|
56
|
+
the confirmation attribute if no reader is defined.
|
57
|
+
|
58
|
+
Example:
|
59
|
+
|
60
|
+
class Blog
|
61
|
+
def title=(new_title)
|
62
|
+
@title = new_title.downcase
|
63
|
+
end
|
64
|
+
|
65
|
+
# previously this would override the setter above.
|
66
|
+
validates_confirmation_of :title
|
67
|
+
end
|
68
|
+
|
69
|
+
*Yves Senn*
|
70
|
+
|
1
71
|
## Rails 4.0.0.beta1 (February 25, 2013) ##
|
2
72
|
|
3
73
|
* Add `ActiveModel::Validations::AbsenceValidator`, a validator to check the
|
@@ -40,7 +110,7 @@
|
|
40
110
|
|
41
111
|
*Yves Senn*
|
42
112
|
|
43
|
-
* Use BCrypt's `MIN_COST` in the test environment for speedier tests when using `
|
113
|
+
* Use BCrypt's `MIN_COST` in the test environment for speedier tests when using `has_secure_password`.
|
44
114
|
|
45
115
|
*Brian Cardarella + Jeremy Kemper + Trevor Turk*
|
46
116
|
|
@@ -81,7 +151,7 @@
|
|
81
151
|
|
82
152
|
* Changed `ActiveModel::Serializers::Xml::Serializer#add_associations` to by default
|
83
153
|
propagate `:skip_types, :dasherize, :camelize` keys to included associations.
|
84
|
-
It can be
|
154
|
+
It can be overridden on each association by explicitly specifying the option on one
|
85
155
|
or more associations
|
86
156
|
|
87
157
|
*Anthony Alberto*
|
data/README.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Active Model provides a known set of interfaces for usage in model classes.
|
4
4
|
They allow for Action Pack helpers to interact with non-Active Record models,
|
5
|
-
for example. Active Model also helps building custom ORMs for use outside of
|
5
|
+
for example. Active Model also helps with building custom ORMs for use outside of
|
6
6
|
the Rails framework.
|
7
7
|
|
8
8
|
Prior to Rails 3.0, if a plugin or gem developer wanted to have an object
|
@@ -24,8 +24,8 @@ to integrate with Action Pack out of the box: <tt>ActiveModel::Model</tt>.
|
|
24
24
|
end
|
25
25
|
|
26
26
|
person = Person.new(name: 'bob', age: '18')
|
27
|
-
person.name
|
28
|
-
person.age
|
27
|
+
person.name # => 'bob'
|
28
|
+
person.age # => '18'
|
29
29
|
person.valid? # => true
|
30
30
|
|
31
31
|
It includes model name introspections, conversions, translations and
|
@@ -82,12 +82,12 @@ behavior out of the box:
|
|
82
82
|
end
|
83
83
|
|
84
84
|
person = Person.new
|
85
|
-
person.name
|
86
|
-
person.changed?
|
85
|
+
person.name # => nil
|
86
|
+
person.changed? # => false
|
87
87
|
person.name = 'bob'
|
88
|
-
person.changed?
|
89
|
-
person.changed
|
90
|
-
person.changes
|
88
|
+
person.changed? # => true
|
89
|
+
person.changed # => ['name']
|
90
|
+
person.changes # => { 'name' => [nil, 'bob'] }
|
91
91
|
person.name = 'robert'
|
92
92
|
person.save
|
93
93
|
person.previous_changes # => {'name' => ['bob, 'robert']}
|
@@ -12,19 +12,21 @@ module ActiveModel
|
|
12
12
|
# # => ActiveModel::MissingAttributeError: missing attribute: user_id
|
13
13
|
class MissingAttributeError < NoMethodError
|
14
14
|
end
|
15
|
+
|
15
16
|
# == Active \Model Attribute Methods
|
16
17
|
#
|
17
18
|
# <tt>ActiveModel::AttributeMethods</tt> provides a way to add prefixes and
|
18
|
-
# suffixes to your methods as well as handling the creation of
|
19
|
-
# like class methods such as +table_name+.
|
19
|
+
# suffixes to your methods as well as handling the creation of
|
20
|
+
# <tt>ActiveRecord::Base</tt>-like class methods such as +table_name+.
|
20
21
|
#
|
21
|
-
# The requirements to implement ActiveModel::AttributeMethods are to:
|
22
|
+
# The requirements to implement <tt>ActiveModel::AttributeMethods</tt> are to:
|
22
23
|
#
|
23
|
-
# * <tt>include ActiveModel::AttributeMethods</tt> in your
|
24
|
-
# * Call each
|
25
|
-
#
|
24
|
+
# * <tt>include ActiveModel::AttributeMethods</tt> in your class.
|
25
|
+
# * Call each of its method you want to add, such as +attribute_method_suffix+
|
26
|
+
# or +attribute_method_prefix+.
|
26
27
|
# * Call +define_attribute_methods+ after the other methods are called.
|
27
28
|
# * Define the various generic +_attribute+ methods that you have declared.
|
29
|
+
# * Define an +attributes+ method, see below.
|
28
30
|
#
|
29
31
|
# A minimal implementation could be:
|
30
32
|
#
|
@@ -38,6 +40,10 @@ module ActiveModel
|
|
38
40
|
#
|
39
41
|
# attr_accessor :name
|
40
42
|
#
|
43
|
+
# def attributes
|
44
|
+
# {'name' => @name}
|
45
|
+
# end
|
46
|
+
#
|
41
47
|
# private
|
42
48
|
#
|
43
49
|
# def attribute_contrived?(attr)
|
@@ -53,10 +59,10 @@ module ActiveModel
|
|
53
59
|
# end
|
54
60
|
# end
|
55
61
|
#
|
56
|
-
# Note that whenever you include ActiveModel::AttributeMethods in
|
57
|
-
# it requires you to implement an +attributes+ method which
|
58
|
-
# with each attribute name in your model as hash key and the
|
59
|
-
# hash value.
|
62
|
+
# Note that whenever you include <tt>ActiveModel::AttributeMethods</tt> in
|
63
|
+
# your class, it requires you to implement an +attributes+ method which
|
64
|
+
# returns a hash with each attribute name in your model as hash key and the
|
65
|
+
# attribute value as hash value.
|
60
66
|
#
|
61
67
|
# Hash keys must be strings.
|
62
68
|
module AttributeMethods
|
@@ -179,7 +185,6 @@ module ActiveModel
|
|
179
185
|
undefine_attribute_methods
|
180
186
|
end
|
181
187
|
|
182
|
-
|
183
188
|
# Allows you to make aliases for attributes.
|
184
189
|
#
|
185
190
|
# class Person
|
@@ -413,17 +418,16 @@ module ActiveModel
|
|
413
418
|
end
|
414
419
|
end
|
415
420
|
|
416
|
-
# Allows access to the object attributes, which are held in the
|
417
|
-
# <tt
|
418
|
-
# Person class with a name attribute can
|
419
|
-
# and never directly use
|
420
|
-
#
|
421
|
-
#
|
422
|
-
# or 0.
|
421
|
+
# Allows access to the object attributes, which are held in the hash
|
422
|
+
# returned by <tt>attributes</tt>, as though they were first-class
|
423
|
+
# methods. So a +Person+ class with a +name+ attribute can for example use
|
424
|
+
# <tt>Person#name</tt> and <tt>Person#name=</tt> and never directly use
|
425
|
+
# the attributes hash -- except for multiple assigns with
|
426
|
+
# <tt>ActiveRecord::Base#attributes=</tt>.
|
423
427
|
#
|
424
|
-
# It's also possible to instantiate related objects, so a Client
|
425
|
-
# belonging to the clients table with a +master_id+ foreign key
|
426
|
-
# instantiate master through Client#master
|
428
|
+
# It's also possible to instantiate related objects, so a <tt>Client</tt>
|
429
|
+
# class belonging to the +clients+ table with a +master_id+ foreign key
|
430
|
+
# can instantiate master through <tt>Client#master</tt>.
|
427
431
|
def method_missing(method, *args, &block)
|
428
432
|
if respond_to_without_attributes?(method, true)
|
429
433
|
super
|
@@ -433,17 +437,17 @@ module ActiveModel
|
|
433
437
|
end
|
434
438
|
end
|
435
439
|
|
436
|
-
# attribute_missing is like method_missing
|
437
|
-
# called we check to see if there is a matching
|
438
|
-
#
|
439
|
-
# customize the behavior.
|
440
|
+
# +attribute_missing+ is like +method_missing+, but for attributes. When
|
441
|
+
# +method_missing+ is called we check to see if there is a matching
|
442
|
+
# attribute method. If so, we tell +attribute_missing+ to dispatch the
|
443
|
+
# attribute. This method can be overloaded to customize the behavior.
|
440
444
|
def attribute_missing(match, *args, &block)
|
441
445
|
__send__(match.target, match.attr_name, *args, &block)
|
442
446
|
end
|
443
447
|
|
444
|
-
# A Person
|
445
|
-
# <tt>person.respond_to?(:name
|
446
|
-
# which will all return +true+.
|
448
|
+
# A +Person+ instance with a +name+ attribute can ask
|
449
|
+
# <tt>person.respond_to?(:name)</tt>, <tt>person.respond_to?(:name=)</tt>,
|
450
|
+
# and <tt>person.respond_to?(:name?)</tt> which will all return +true+.
|
447
451
|
alias :respond_to_without_attributes? :respond_to?
|
448
452
|
def respond_to?(method, include_private_methods = false)
|
449
453
|
if super
|
data/lib/active_model/dirty.rb
CHANGED
data/lib/active_model/errors.rb
CHANGED
@@ -12,7 +12,6 @@ module ActiveModel
|
|
12
12
|
# A minimal implementation could be:
|
13
13
|
#
|
14
14
|
# class Person
|
15
|
-
#
|
16
15
|
# # Required dependency for ActiveModel::Errors
|
17
16
|
# extend ActiveModel::Naming
|
18
17
|
#
|
@@ -40,7 +39,6 @@ module ActiveModel
|
|
40
39
|
# def Person.lookup_ancestors
|
41
40
|
# [self]
|
42
41
|
# end
|
43
|
-
#
|
44
42
|
# end
|
45
43
|
#
|
46
44
|
# The last three methods are required in your object for Errors to be
|
@@ -352,6 +350,20 @@ module ActiveModel
|
|
352
350
|
map { |attribute, message| full_message(attribute, message) }
|
353
351
|
end
|
354
352
|
|
353
|
+
# Returns all the full error messages for a given attribute in an array.
|
354
|
+
#
|
355
|
+
# class Person
|
356
|
+
# validates_presence_of :name, :email
|
357
|
+
# validates_length_of :name, in: 5..30
|
358
|
+
# end
|
359
|
+
#
|
360
|
+
# person = Person.create()
|
361
|
+
# person.errors.full_messages_for(:name)
|
362
|
+
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank"]
|
363
|
+
def full_messages_for(attribute)
|
364
|
+
(get(attribute) || []).map { |message| full_message(attribute, message) }
|
365
|
+
end
|
366
|
+
|
355
367
|
# Returns a full message for a given attribute.
|
356
368
|
#
|
357
369
|
# person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
|
@@ -30,24 +30,31 @@ module ActiveModel
|
|
30
30
|
# end
|
31
31
|
#
|
32
32
|
# user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
|
33
|
-
# user.save
|
33
|
+
# user.save # => false, password required
|
34
34
|
# user.password = 'mUc3m00RsqyRe'
|
35
|
-
# user.save
|
35
|
+
# user.save # => false, confirmation doesn't match
|
36
36
|
# user.password_confirmation = 'mUc3m00RsqyRe'
|
37
|
-
# user.save
|
38
|
-
# user.authenticate('notright')
|
39
|
-
# user.authenticate('mUc3m00RsqyRe')
|
40
|
-
# User.
|
41
|
-
# User.
|
37
|
+
# user.save # => true
|
38
|
+
# user.authenticate('notright') # => false
|
39
|
+
# user.authenticate('mUc3m00RsqyRe') # => user
|
40
|
+
# User.find_by(name: 'david').try(:authenticate, 'notright') # => false
|
41
|
+
# User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user
|
42
42
|
def has_secure_password(options = {})
|
43
43
|
# Load bcrypt-ruby only when has_secure_password is used.
|
44
44
|
# This is to avoid ActiveModel (and by extension the entire framework)
|
45
45
|
# being dependent on a binary library.
|
46
|
-
|
47
|
-
|
46
|
+
begin
|
47
|
+
gem 'bcrypt-ruby', '~> 3.0.0'
|
48
|
+
require 'bcrypt'
|
49
|
+
rescue LoadError
|
50
|
+
$stderr.puts "You don't have bcrypt-ruby installed in your application. Please add it to your Gemfile and run bundle install"
|
51
|
+
raise
|
52
|
+
end
|
48
53
|
|
49
54
|
attr_reader :password
|
50
55
|
|
56
|
+
include InstanceMethodsOnActivation
|
57
|
+
|
51
58
|
if options.fetch(:validations, true)
|
52
59
|
validates_confirmation_of :password
|
53
60
|
validates_presence_of :password, :on => :create
|
@@ -55,8 +62,6 @@ module ActiveModel
|
|
55
62
|
before_create { raise "Password digest missing on new record" if password_digest.blank? }
|
56
63
|
end
|
57
64
|
|
58
|
-
include InstanceMethodsOnActivation
|
59
|
-
|
60
65
|
if respond_to?(:attributes_protected_by_default)
|
61
66
|
def self.attributes_protected_by_default #:nodoc:
|
62
67
|
super + ['password_digest']
|
@@ -99,6 +104,12 @@ module ActiveModel
|
|
99
104
|
self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost)
|
100
105
|
end
|
101
106
|
end
|
107
|
+
|
108
|
+
def password_confirmation=(unencrypted_password)
|
109
|
+
unless unencrypted_password.blank?
|
110
|
+
@password_confirmation = unencrypted_password
|
111
|
+
end
|
112
|
+
end
|
102
113
|
end
|
103
114
|
end
|
104
115
|
end
|
@@ -169,6 +169,49 @@ module ActiveModel
|
|
169
169
|
_validators.values.flatten.uniq
|
170
170
|
end
|
171
171
|
|
172
|
+
# Clears all of the validators and validations.
|
173
|
+
#
|
174
|
+
# Note that this will clear anything that is being used to validate
|
175
|
+
# the model for both the +validates_with+ and +validate+ methods.
|
176
|
+
# It clears the validators that are created with an invocation of
|
177
|
+
# +validates_with+ and the callbacks that are set by an invocation
|
178
|
+
# of +validate+.
|
179
|
+
#
|
180
|
+
# class Person
|
181
|
+
# include ActiveModel::Validations
|
182
|
+
#
|
183
|
+
# validates_with MyValidator
|
184
|
+
# validates_with OtherValidator, on: :create
|
185
|
+
# validates_with StrictValidator, strict: true
|
186
|
+
# validate :cannot_be_robot
|
187
|
+
#
|
188
|
+
# def cannot_be_robot
|
189
|
+
# errors.add(:base, 'A person cannot be a robot') if person_is_robot
|
190
|
+
# end
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
# Person.validators
|
194
|
+
# # => [
|
195
|
+
# # #<MyValidator:0x007fbff403e808 @options={}>,
|
196
|
+
# # #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
|
197
|
+
# # #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
|
198
|
+
# # ]
|
199
|
+
#
|
200
|
+
# If one runs Person.clear_validators! and then checks to see what
|
201
|
+
# validators this class has, you would obtain:
|
202
|
+
#
|
203
|
+
# Person.validators # => []
|
204
|
+
#
|
205
|
+
# Also, the callback set by +validate :cannot_be_robot+ will be erased
|
206
|
+
# so that:
|
207
|
+
#
|
208
|
+
# Person._validate_callbacks.empty? # => true
|
209
|
+
#
|
210
|
+
def clear_validators!
|
211
|
+
reset_callbacks(:validate)
|
212
|
+
_validators.clear
|
213
|
+
end
|
214
|
+
|
172
215
|
# List all validators that are being used to validate a specific attribute.
|
173
216
|
#
|
174
217
|
# class Person
|
@@ -333,7 +376,4 @@ module ActiveModel
|
|
333
376
|
end
|
334
377
|
end
|
335
378
|
|
336
|
-
Dir[File.dirname(__FILE__) + "/validations/*.rb"].
|
337
|
-
filename = File.basename(path)
|
338
|
-
require "active_model/validations/#{filename}"
|
339
|
-
end
|
379
|
+
Dir[File.dirname(__FILE__) + "/validations/*.rb"].each { |file| require file }
|
@@ -10,9 +10,13 @@ module ActiveModel
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def setup(klass)
|
13
|
-
klass.send(:
|
13
|
+
klass.send(:attr_reader, *attributes.map do |attribute|
|
14
14
|
:"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation")
|
15
15
|
end.compact)
|
16
|
+
|
17
|
+
klass.send(:attr_writer, *attributes.map do |attribute|
|
18
|
+
:"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=")
|
19
|
+
end.compact)
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
data/lib/active_model/version.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module ActiveModel
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
PRE = "beta1"
|
2
|
+
# Returns the version of the currently loaded ActiveModel as a Gem::Version
|
3
|
+
def self.version
|
4
|
+
Gem::Version.new "4.0.0.rc1"
|
5
|
+
end
|
7
6
|
|
8
|
-
|
7
|
+
module VERSION #:nodoc:
|
8
|
+
MAJOR, MINOR, TINY, PRE = ActiveModel.version.segments
|
9
|
+
STRING = ActiveModel.version.to_s
|
9
10
|
end
|
10
11
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.0.
|
4
|
+
version: 4.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 4.0.0.
|
19
|
+
version: 4.0.0.rc1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 4.0.0.
|
26
|
+
version: 4.0.0.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: builder
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|