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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a123b304fffb488ab66aab52d5fc0d41b0c0b511
4
- data.tar.gz: 1890c14c3ab9251044e70e38f993d4c55707cb52
3
+ metadata.gz: 250ef70b10d4ec2e30333cfffc80da63aed87895
4
+ data.tar.gz: 69c232cc5ed875faedbb29a0f0d6c1a01bcf5d19
5
5
  SHA512:
6
- metadata.gz: 882ad1f17ccb90c6a79d86a42d3f91685a1ece5e7ec63ed83be888a20d086ea38928aba2af650e13b79c1955d5f62d78c4b865311be1a8ae065197ee2a858aaa
7
- data.tar.gz: 5452a0c0afabc7f3c3f536e670cb61244dd8d9236bfac6dd049da917dbe6bed0d110b4c6ed3bd0a374c7e09b42988cd937ae57cef83ff03e42a33aeea2cbb276
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 `has_secure_pasword`.
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 overriden on each association by explicitly specifying the option on one
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 # => 'bob'
28
- person.age # => '18'
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 # => nil
86
- person.changed? # => false
85
+ person.name # => nil
86
+ person.changed? # => false
87
87
  person.name = 'bob'
88
- person.changed? # => true
89
- person.changed # => ['name']
90
- person.changes # => { 'name' => [nil, 'bob'] }
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 Active Record
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 object.
24
- # * Call each Attribute Method module method you want to add, such as
25
- # +attribute_method_suffix+ or +attribute_method_prefix+.
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 your class,
57
- # it requires you to implement an +attributes+ method which returns a hash
58
- # with each attribute name in your model as hash key and the attribute value as
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>@attributes</tt> hash, as though they were first-class methods. So a
418
- # Person class with a name attribute can use Person#name and Person#name=
419
- # and never directly use the attributes hash -- except for multiple assigns
420
- # with ActiveRecord#attributes=. A Milestone class can also ask
421
- # Milestone#completed? to test that the completed attribute is not +nil+
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 class
425
- # belonging to the clients table with a +master_id+ foreign key can
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, but for attributes. When method_missing is
437
- # called we check to see if there is a matching attribute method. If so, we call
438
- # attribute_missing to dispatch the attribute. This method can be overloaded to
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 object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
445
- # <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
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
@@ -1,5 +1,5 @@
1
1
  module ActiveModel
2
- # == Active \Model Conversions
2
+ # == Active \Model Conversion
3
3
  #
4
4
  # Handles default conversions: to_model, to_key, to_param, and to_partial_path.
5
5
  #
@@ -46,7 +46,7 @@ module ActiveModel
46
46
  #
47
47
  # A newly instantiated object is unchanged:
48
48
  #
49
- # person = Person.find_by_name('Uncle Bob')
49
+ # person = Person.find_by(name: 'Uncle Bob')
50
50
  # person.changed? # => false
51
51
  #
52
52
  # Change the name:
@@ -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 # => false, password required
33
+ # user.save # => false, password required
34
34
  # user.password = 'mUc3m00RsqyRe'
35
- # user.save # => false, confirmation doesn't match
35
+ # user.save # => false, confirmation doesn't match
36
36
  # user.password_confirmation = 'mUc3m00RsqyRe'
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
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
- gem 'bcrypt-ruby', '~> 3.0.0'
47
- require 'bcrypt'
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"].sort.each do |path|
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(:attr_accessor, *attributes.map do |attribute|
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
 
@@ -1,10 +1,11 @@
1
1
  module ActiveModel
2
- module VERSION #:nodoc:
3
- MAJOR = 4
4
- MINOR = 0
5
- TINY = 0
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
- STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
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.beta1
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-02-26 00:00:00.000000000 Z
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.beta1
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.beta1
26
+ version: 4.0.0.rc1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: builder
29
29
  requirement: !ruby/object:Gem::Requirement