mongomatic 0.1.4 → 0.1.31
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +26 -90
- data/lib/mongomatic.rb +2 -1
- data/lib/mongomatic/base.rb +2 -14
- data/lib/mongomatic/validatable.rb +31 -0
- data/lib/mongomatic/validatable/child_validation.rb +17 -0
- data/lib/mongomatic/validatable/errors.rb +108 -0
- data/lib/mongomatic/validatable/included_validation.rb +11 -0
- data/lib/mongomatic/validatable/macros.rb +316 -0
- data/lib/mongomatic/validatable/object_extension.rb +21 -0
- data/lib/mongomatic/validatable/requireable.rb +28 -0
- data/lib/mongomatic/validatable/understandable.rb +33 -0
- data/lib/mongomatic/validatable/validatable_class_methods.rb +89 -0
- data/lib/mongomatic/validatable/validatable_instance_methods.rb +111 -0
- data/lib/mongomatic/validatable/validations/validates_acceptance_of.rb +16 -0
- data/lib/mongomatic/validatable/validations/validates_associated.rb +15 -0
- data/lib/mongomatic/validatable/validations/validates_confirmation_of.rb +25 -0
- data/lib/mongomatic/validatable/validations/validates_each.rb +16 -0
- data/lib/mongomatic/validatable/validations/validates_exclusion_of.rb +19 -0
- data/lib/mongomatic/validatable/validations/validates_format_of.rb +18 -0
- data/lib/mongomatic/validatable/validations/validates_inclusion_of.rb +19 -0
- data/lib/mongomatic/validatable/validations/validates_length_of.rb +32 -0
- data/lib/mongomatic/validatable/validations/validates_numericality_of.rb +28 -0
- data/lib/mongomatic/validatable/validations/validates_presence_of.rb +18 -0
- data/lib/mongomatic/validatable/validations/validates_true_for.rb +15 -0
- data/lib/mongomatic/validatable/validations/validation_base.rb +93 -0
- data/test/helper.rb +1 -4
- metadata +24 -3
- data/lib/mongomatic/errors.rb +0 -7
data/README.rdoc
CHANGED
@@ -2,23 +2,12 @@
|
|
2
2
|
|
3
3
|
Mongomatic allows you to map your Ruby objects to Mongo documents. It is designed to be fast and simple.
|
4
4
|
|
5
|
-
== What's different about Mongomatic?
|
6
|
-
|
7
|
-
* Follows Mongo idioms wherever possible.
|
8
|
-
* Only strives to do "just enough" and never too much.
|
9
|
-
* When possible, we defer to Mongo. For example, there's no Mongomatic query API, instead you use the same query hash syntax you would with the Ruby Mongo driver.
|
10
|
-
* No complex relationship management: if you want to model relationships then add your own finder methods.
|
11
|
-
* Minimal dependencies.
|
12
|
-
|
13
5
|
== Basic Usage
|
14
6
|
|
15
7
|
require 'mongomatic'
|
16
8
|
|
17
9
|
class User < Mongomatic::Base
|
18
|
-
|
19
|
-
self.errors << ["Name", "can't be empty"] if self["name"].blank?
|
20
|
-
self.errors << ["Email", "can't be empty"] if self["email"].blank?
|
21
|
-
end
|
10
|
+
validates_presence_of :name, :email
|
22
11
|
end
|
23
12
|
|
24
13
|
# set the db for all models:
|
@@ -35,33 +24,42 @@ Mongomatic allows you to map your Ruby objects to Mongo documents. It is designe
|
|
35
24
|
=> true
|
36
25
|
u.insert
|
37
26
|
=> BSON::ObjectID('4c32834f0218236321000001')
|
38
|
-
|
27
|
+
u
|
28
|
+
=> #<User:0x00000100d0cbf8 @doc={"name"=>"Ben", "email"=>"me@somewhere.com", "_id"=>BSON::ObjectID('4c32834f0218236321000001')}, @removed=false, @validation_context=nil, @errors={}, @_initialized_validate_callbacks=true>
|
39
29
|
u["name"] = "Ben Myles"
|
40
30
|
=> "Ben Myles"
|
41
31
|
u.update
|
42
|
-
=>
|
43
|
-
|
44
|
-
found = User.find_one({"name" => "Ben Myles"})
|
45
|
-
=> #<User:0x00000101939a48 @doc={"_id"=>BSON::ObjectID('4c32834f0218236321000001'), "name"=>"Ben Myles", "email"=>"me@somewhere.com"}, @removed=false, @is_new=false, @errors=[]>
|
46
|
-
User.find_one(BSON::ObjectID('4c32834f0218236321000001')) == found
|
47
|
-
=> true
|
32
|
+
=> 142
|
48
33
|
|
49
34
|
cursor = User.find({"name" => "Ben Myles"})
|
50
|
-
=> #<Mongomatic::Cursor:
|
35
|
+
=> #<Mongomatic::Cursor:0x00000100cf5110 @obj_class=User, @mongo_cursor=DBResponse(flags=, cursor_id=, start=)> cursor.count
|
36
|
+
cursor.count
|
37
|
+
=> 1
|
51
38
|
found = cursor.next
|
52
|
-
=> #<User:
|
39
|
+
=> #<User:0x00000100ccd408 @doc={"_id"=>BSON::ObjectID('4c32c3720218236526000001'), "name"=>"Ben Myles", "email"=>"me@somewhere.com"}, @removed=false>
|
53
40
|
found.remove
|
54
|
-
=>
|
55
|
-
|
56
|
-
=>
|
57
|
-
User.find({"name" => "Ben Myles"})
|
41
|
+
=> 72
|
42
|
+
found
|
43
|
+
=> #<User:0x00000101091f80 @doc={"_id"=>BSON::ObjectID('4c32c4480218236538000001'), "name"=>"Ben Myles", "email"=>"me@somewhere.com"}, @removed=true>
|
44
|
+
cursor = User.find({"name" => "Ben Myles"})
|
45
|
+
=> #<Mongomatic::Cursor:0x00000100d9eb20 @obj_class=User, @mongo_cursor=DBResponse(flags=, cursor_id=, start=)>
|
46
|
+
cursor.count
|
47
|
+
=> 0
|
48
|
+
cursor.next
|
58
49
|
=> nil
|
59
|
-
|
50
|
+
|
51
|
+
found = User.find_one({"name" => "Ben Myles"})
|
52
|
+
=> #<User:0x00000100ccd408 @doc={"_id"=>BSON::ObjectID('4c32c3720218236526000001'), "name"=>"Ben Myles", "email"=>"me@somewhere.com"}, @removed=false>
|
53
|
+
found = User.find_one(BSON::ObjectID('4c32c3720218236526000001'))
|
54
|
+
=> #<User:0x00000100ccd408 @doc={"_id"=>BSON::ObjectID('4c32c3720218236526000001'), "name"=>"Ben Myles", "email"=>"me@somewhere.com"}, @removed=false>
|
55
|
+
|
60
56
|
== Indexes
|
61
57
|
|
62
58
|
Mongomatic doesn't do anything special to support indexes, but here's the suggested convention:
|
63
59
|
|
64
|
-
class Person < Mongomatic::Base
|
60
|
+
class Person < Mongomatic::Base
|
61
|
+
validates_presence_of :name, :email
|
62
|
+
|
65
63
|
class << self
|
66
64
|
def create_indexes
|
67
65
|
collection.create_index("email", :unique => true)
|
@@ -71,69 +69,7 @@ Mongomatic doesn't do anything special to support indexes, but here's the sugges
|
|
71
69
|
|
72
70
|
You can run Person.create_indexes whenever you add new indexes, it won't throw an error if they already exist.
|
73
71
|
|
74
|
-
If you have defined a unique index and want Mongomatic to raise an exception on a duplicate insert you need to use
|
75
|
-
|
76
|
-
== Validations
|
77
|
-
|
78
|
-
You can add validations to your model by creating a validate method. If your validate method pushes anything into the self.errors object your model will fail to validate, otherwise if self.errors remains empty the validations will be taken to have passed.
|
79
|
-
|
80
|
-
class Person < Mongomatic::Base
|
81
|
-
def validate
|
82
|
-
self.errors << ["name", "blank"] if self["name"].blank?
|
83
|
-
self.errors << ["email", "blank"] if self["email"].blank?
|
84
|
-
self.errors << ["address.zip", "blank"] if (self["address"] || {})["zip"].blank?
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
p = Person.new
|
89
|
-
=> #<Person:0x000001018c2d58 @doc={}, @removed=false, @is_new=true, @errors=[]>
|
90
|
-
p.valid?
|
91
|
-
=> false
|
92
|
-
p.errors
|
93
|
-
=> [["name", "blank"], ["email", "blank"], ["address.zip", "blank"]]
|
94
|
-
p.errors.full_messages
|
95
|
-
=> ["name blank", "email blank", "address.zip blank"]
|
96
|
-
p["name"] = "Ben"
|
97
|
-
p["email"] = "Myles"
|
98
|
-
p["address"] = { "zip" => 94107 }
|
99
|
-
p.valid?
|
100
|
-
=> true
|
101
|
-
|
102
|
-
== Relationships
|
103
|
-
|
104
|
-
Mongomatic doesn't have any kind of special support for relationship management but it's easy to add this to your models where you need it. Here's an example that models Twitter-like followers on a User model:
|
105
|
-
|
106
|
-
class User < Mongomatic::Base
|
107
|
-
class << self
|
108
|
-
def create_indexes
|
109
|
-
self.collection.create_index("following_ids")
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def follow(user)
|
114
|
-
self.push("following_ids", user["_id"])
|
115
|
-
end
|
116
|
-
|
117
|
-
def unfollow(user)
|
118
|
-
self.pull("following_ids", user["_id"])
|
119
|
-
end
|
120
|
-
|
121
|
-
def following
|
122
|
-
return nil if new?
|
123
|
-
self.class.find( { "_id" => { "$in" => (self["following_ids"] || []) } } )
|
124
|
-
end
|
125
|
-
|
126
|
-
def followers
|
127
|
-
return nil if new?
|
128
|
-
self.class.find( { "following_ids" => self["_id"] } )
|
129
|
-
end
|
130
|
-
|
131
|
-
def friends
|
132
|
-
return nil if new?
|
133
|
-
self.class.find( { "following_ids" => self["_id"],
|
134
|
-
"_id" => { "$in" => (self["following_ids"] || []) } } )
|
135
|
-
end
|
136
|
-
end
|
72
|
+
If you have defined a unique index and want Mongomatic to raise an exception on a duplicate insert you need to use insert_safe or update_safe. The error thrown will be Mongo::OperationFailure. See the test suite for examples.
|
137
73
|
|
138
74
|
== Note on Patches/Pull Requests
|
139
75
|
|
data/lib/mongomatic.rb
CHANGED
@@ -27,7 +27,8 @@ module Mongomatic
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
require "#{File.dirname(__FILE__)}/mongomatic/validatable"
|
31
|
+
|
30
32
|
require "#{File.dirname(__FILE__)}/mongomatic/cursor"
|
31
33
|
require "#{File.dirname(__FILE__)}/mongomatic/modifiers"
|
32
|
-
require "#{File.dirname(__FILE__)}/mongomatic/errors"
|
33
34
|
require "#{File.dirname(__FILE__)}/mongomatic/base"
|
data/lib/mongomatic/base.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Mongomatic
|
2
2
|
class Base
|
3
3
|
include Mongomatic::Modifiers
|
4
|
+
include Mongomatic::Validatable
|
4
5
|
|
5
6
|
class << self
|
6
7
|
def db
|
@@ -47,25 +48,12 @@ module Mongomatic
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
attr_accessor :removed, :is_new
|
51
|
+
attr_accessor :removed, :is_new
|
51
52
|
|
52
53
|
def initialize(doc={}, is_new=true)
|
53
54
|
@doc = doc.stringify_keys
|
54
55
|
self.removed = false
|
55
56
|
self.is_new = is_new
|
56
|
-
self.errors = Mongomatic::Errors.new
|
57
|
-
end
|
58
|
-
|
59
|
-
def validate
|
60
|
-
true
|
61
|
-
end
|
62
|
-
|
63
|
-
def valid?
|
64
|
-
self.errors = Mongomatic::Errors.new
|
65
|
-
self.send(:before_validate) if self.respond_to?(:before_validate)
|
66
|
-
validate
|
67
|
-
self.send(:after_validate) if self.respond_to?(:after_validate)
|
68
|
-
self.errors.empty?
|
69
57
|
end
|
70
58
|
|
71
59
|
def is_new?
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# gem "activesupport", "2.3.5"
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
require "#{File.dirname(__FILE__)}/validatable/object_extension"
|
6
|
+
require "#{File.dirname(__FILE__)}/validatable/errors"
|
7
|
+
require "#{File.dirname(__FILE__)}/validatable/validatable_class_methods"
|
8
|
+
require "#{File.dirname(__FILE__)}/validatable/macros"
|
9
|
+
require "#{File.dirname(__FILE__)}/validatable/validatable_instance_methods"
|
10
|
+
require "#{File.dirname(__FILE__)}/validatable/included_validation"
|
11
|
+
require "#{File.dirname(__FILE__)}/validatable/child_validation"
|
12
|
+
require "#{File.dirname(__FILE__)}/validatable/understandable"
|
13
|
+
require "#{File.dirname(__FILE__)}/validatable/requireable"
|
14
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validation_base"
|
15
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_format_of"
|
16
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_presence_of"
|
17
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_acceptance_of"
|
18
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_confirmation_of"
|
19
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_length_of"
|
20
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_true_for"
|
21
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_numericality_of"
|
22
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_exclusion_of"
|
23
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_inclusion_of"
|
24
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_each"
|
25
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_associated"
|
26
|
+
|
27
|
+
module Mongomatic
|
28
|
+
module Validatable
|
29
|
+
Version = "1.8.4"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Mongomatic
|
2
|
+
module Validatable
|
3
|
+
class ChildValidation #:nodoc:
|
4
|
+
attr_accessor :attribute, :map, :should_validate_proc
|
5
|
+
|
6
|
+
def initialize(attribute, map, should_validate_proc)
|
7
|
+
@attribute = attribute
|
8
|
+
@map = map
|
9
|
+
@should_validate_proc = should_validate_proc
|
10
|
+
end
|
11
|
+
|
12
|
+
def should_validate?(instance)
|
13
|
+
instance.instance_eval &should_validate_proc
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Mongomatic
|
2
|
+
module Validatable
|
3
|
+
class Errors
|
4
|
+
extend Forwardable
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def_delegators :errors, :clear, :each, :each_pair, :empty?, :length, :size
|
8
|
+
|
9
|
+
# Returns true if the specified +attribute+ has errors associated with it.
|
10
|
+
#
|
11
|
+
# class Company < ActiveRecord::Base
|
12
|
+
# validates_presence_of :name, :address, :email
|
13
|
+
# validates_length_of :name, :in => 5..30
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# company = Company.create(:address => '123 First St.')
|
17
|
+
# company.errors.invalid?(:name) # => true
|
18
|
+
# company.errors.invalid?(:address) # => false
|
19
|
+
def invalid?(attribute)
|
20
|
+
!@errors[attribute.to_sym].nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adds an error to the base object instead of any particular attribute. This is used
|
24
|
+
# to report errors that don't tie to any specific attribute, but rather to the object
|
25
|
+
# as a whole. These error messages don't get prepended with any field name when iterating
|
26
|
+
# with +each_full+, so they should be complete sentences.
|
27
|
+
def add_to_base(msg)
|
28
|
+
add(:base, msg)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns errors assigned to the base object through +add_to_base+ according to the normal rules of <tt>on(attribute)</tt>.
|
32
|
+
def on_base
|
33
|
+
on(:base)
|
34
|
+
end
|
35
|
+
|
36
|
+
# call-seq: on(attribute)
|
37
|
+
#
|
38
|
+
# * Returns nil, if no errors are associated with the specified +attribute+.
|
39
|
+
# * Returns the error message, if one error is associated with the specified +attribute+.
|
40
|
+
# * Returns an array of error messages, if more than one error is associated with the specified +attribute+.
|
41
|
+
def on(attribute)
|
42
|
+
return nil if errors[attribute.to_sym].nil?
|
43
|
+
errors[attribute.to_sym].size == 1 ? errors[attribute.to_sym].first : errors[attribute.to_sym]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Rails 3 API for errors, always return array.
|
47
|
+
def [](attribute)
|
48
|
+
errors[attribute.to_sym] || []
|
49
|
+
end
|
50
|
+
|
51
|
+
def add(attribute, message) #:nodoc:
|
52
|
+
errors[attribute.to_sym] = [] if errors[attribute.to_sym].nil?
|
53
|
+
errors[attribute.to_sym] << message
|
54
|
+
end
|
55
|
+
|
56
|
+
def merge!(errors) #:nodoc:
|
57
|
+
errors.each_pair{|k, v| add(k,v)}
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
# call-seq: replace(attribute)
|
62
|
+
#
|
63
|
+
# * Replaces the errors value for the given +attribute+
|
64
|
+
def replace(attribute, value)
|
65
|
+
errors[attribute.to_sym] = value
|
66
|
+
end
|
67
|
+
|
68
|
+
# call-seq: raw(attribute)
|
69
|
+
#
|
70
|
+
# * Returns an array of error messages associated with the specified +attribute+.
|
71
|
+
def raw(attribute)
|
72
|
+
errors[attribute.to_sym]
|
73
|
+
end
|
74
|
+
|
75
|
+
def errors #:nodoc:
|
76
|
+
@errors ||= {}
|
77
|
+
end
|
78
|
+
|
79
|
+
def count #:nodoc:
|
80
|
+
errors.values.flatten.size
|
81
|
+
end
|
82
|
+
|
83
|
+
# call-seq: full_messages -> an_array_of_messages
|
84
|
+
#
|
85
|
+
# Returns an array containing the full list of error messages.
|
86
|
+
def full_messages
|
87
|
+
full_messages = []
|
88
|
+
|
89
|
+
errors.each_key do |attribute|
|
90
|
+
errors[attribute].each do |msg|
|
91
|
+
next if msg.nil?
|
92
|
+
|
93
|
+
if attribute.to_s == "base"
|
94
|
+
full_messages << msg
|
95
|
+
else
|
96
|
+
full_messages << humanize(attribute.to_s) + " " + msg
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
full_messages
|
101
|
+
end
|
102
|
+
|
103
|
+
def humanize(lower_case_and_underscored_word) #:nodoc:
|
104
|
+
lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
module Mongomatic
|
2
|
+
module Validatable
|
3
|
+
module Macros
|
4
|
+
# call-seq: validates_each(*args)
|
5
|
+
#
|
6
|
+
# Validates that the logic evaluates to true
|
7
|
+
#
|
8
|
+
# class Address
|
9
|
+
# include Validatable
|
10
|
+
# validates_each :zip_code, :logic => lambda { errors.add(:zip_code, "is not valid") if ZipCodeService.allows(zip_code) }
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# The logic option is required.
|
14
|
+
#
|
15
|
+
# Configuration options:
|
16
|
+
#
|
17
|
+
# * after_validate - A block that executes following the run of a validation
|
18
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
19
|
+
# * if - A block that when executed must return true of the validation will not occur
|
20
|
+
# * level - The level at which the validation should occur
|
21
|
+
# * logic - A block that executes to perform the validation
|
22
|
+
# * message - The message to add to the errors collection when the validation fails
|
23
|
+
# * times - The number of times the validation applies
|
24
|
+
def validates_each(*args)
|
25
|
+
add_validations(args, ValidatesEach)
|
26
|
+
end
|
27
|
+
|
28
|
+
# call-seq: validates_format_of(*args)
|
29
|
+
#
|
30
|
+
# Validates whether the value of the specified attribute is of the
|
31
|
+
# correct form by matching it against the regular expression provided.
|
32
|
+
#
|
33
|
+
# class Person
|
34
|
+
# include Validatable
|
35
|
+
# validates_format_of :first_name, :with => /[ A-Za-z]/
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# A regular expression must be provided or else an exception will be raised.
|
39
|
+
#
|
40
|
+
# Configuration options:
|
41
|
+
#
|
42
|
+
# * after_validate - A block that executes following the run of a validation
|
43
|
+
# * message - The message to add to the errors collection when the validation fails
|
44
|
+
# * times - The number of times the validation applies
|
45
|
+
# * level - The level at which the validation should occur
|
46
|
+
# * if - A block that when executed must return true of the validation will not occur
|
47
|
+
# * with - The regular expression used to validate the format
|
48
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
49
|
+
def validates_format_of(*args)
|
50
|
+
add_validations(args, ValidatesFormatOf)
|
51
|
+
end
|
52
|
+
|
53
|
+
# call-seq: validates_length_of(*args)
|
54
|
+
#
|
55
|
+
# Validates that the specified attribute matches the length restrictions supplied.
|
56
|
+
#
|
57
|
+
# class Person
|
58
|
+
# include Validatable
|
59
|
+
# validates_length_of :first_name, :maximum=>30
|
60
|
+
# validates_length_of :last_name, :minimum=>30
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# Configuration options:
|
64
|
+
#
|
65
|
+
# * after_validate - A block that executes following the run of a validation
|
66
|
+
# * message - The message to add to the errors collection when the validation fails
|
67
|
+
# * times - The number of times the validation applies
|
68
|
+
# * level - The level at which the validation should occur
|
69
|
+
# * if - A block that when executed must return true of the validation will not occur
|
70
|
+
# * minimum - The minimum size of the attribute
|
71
|
+
# * maximum - The maximum size of the attribute
|
72
|
+
# * is - The size the attribute must be
|
73
|
+
# * within - A range that the size of the attribute must fall within
|
74
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
75
|
+
def validates_length_of(*args)
|
76
|
+
add_validations(args, ValidatesLengthOf)
|
77
|
+
end
|
78
|
+
|
79
|
+
# call-seq: validates_numericality_of(*args)
|
80
|
+
#
|
81
|
+
# Validates that the specified attribute is numeric.
|
82
|
+
#
|
83
|
+
# class Person
|
84
|
+
# include Validatable
|
85
|
+
# validates_numericality_of :age
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# Configuration options:
|
89
|
+
#
|
90
|
+
# * after_validate - A block that executes following the run of a validation
|
91
|
+
# * message - The message to add to the errors collection when the validation fails
|
92
|
+
# * times - The number of times the validation applies
|
93
|
+
# * level - The level at which the validation should occur
|
94
|
+
# * if - A block that when executed must return true of the validation will not occur
|
95
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
96
|
+
# * only_integer - Whether the attribute must be an integer (default is false)
|
97
|
+
def validates_numericality_of(*args)
|
98
|
+
add_validations(args, ValidatesNumericalityOf)
|
99
|
+
end
|
100
|
+
|
101
|
+
# call-seq: validates_acceptance_of(*args)
|
102
|
+
#
|
103
|
+
# Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
|
104
|
+
#
|
105
|
+
# class Person
|
106
|
+
# include Validatable
|
107
|
+
# validates_acceptance_of :terms_of_service
|
108
|
+
# validates_acceptance_of :eula, :message => "must be abided"
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# Configuration options:
|
112
|
+
#
|
113
|
+
# * after_validate - A block that executes following the run of a validation
|
114
|
+
# * message - The message to add to the errors collection when the validation fails
|
115
|
+
# * times - The number of times the validation applies
|
116
|
+
# * level - The level at which the validation should occur
|
117
|
+
# * if - A block that when executed must return true of the validation will not occur
|
118
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
119
|
+
def validates_acceptance_of(*args)
|
120
|
+
add_validations(args, ValidatesAcceptanceOf)
|
121
|
+
end
|
122
|
+
|
123
|
+
# call-seq: validates_confirmation_of(*args)
|
124
|
+
#
|
125
|
+
# Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
|
126
|
+
#
|
127
|
+
# Class:
|
128
|
+
# class PersonPresenter
|
129
|
+
# include Validatable
|
130
|
+
# validates_confirmation_of :user_name, :password
|
131
|
+
# validates_confirmation_of :email_address, :message => "should match confirmation"
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# View:
|
135
|
+
# <%= password_field "person", "password" %>
|
136
|
+
# <%= password_field "person", "password_confirmation" %>
|
137
|
+
#
|
138
|
+
# Configuration options:
|
139
|
+
#
|
140
|
+
# * after_validate - A block that executes following the run of a validation
|
141
|
+
# * case_sensitive - Whether or not to apply case-sensitivity on the comparison. Defaults to true.
|
142
|
+
# * message - The message to add to the errors collection when the validation fails
|
143
|
+
# * times - The number of times the validation applies
|
144
|
+
# * level - The level at which the validation should occur
|
145
|
+
# * if - A block that when executed must return true of the validation will not occur
|
146
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
147
|
+
def validates_confirmation_of(*args)
|
148
|
+
add_validations(args, ValidatesConfirmationOf)
|
149
|
+
end
|
150
|
+
|
151
|
+
# call-seq: validates_presence_of(*args)
|
152
|
+
#
|
153
|
+
# Validates that the specified attributes are not nil or an empty string
|
154
|
+
#
|
155
|
+
# class Person
|
156
|
+
# include Validatable
|
157
|
+
# validates_presence_of :first_name
|
158
|
+
# end
|
159
|
+
#
|
160
|
+
# The first_name attribute must be in the object and it cannot be nil or empty.
|
161
|
+
#
|
162
|
+
# Configuration options:
|
163
|
+
#
|
164
|
+
# * after_validate - A block that executes following the run of a validation
|
165
|
+
# * message - The message to add to the errors collection when the validation fails
|
166
|
+
# * times - The number of times the validation applies
|
167
|
+
# * level - The level at which the validation should occur
|
168
|
+
# * if - A block that when executed must return true of the validation will not occur
|
169
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
170
|
+
def validates_presence_of(*args)
|
171
|
+
add_validations(args, ValidatesPresenceOf)
|
172
|
+
end
|
173
|
+
|
174
|
+
# call-seq: validates_true_for(*args)
|
175
|
+
#
|
176
|
+
# Validates that the logic evaluates to true
|
177
|
+
#
|
178
|
+
# class Person
|
179
|
+
# include Validatable
|
180
|
+
# validates_true_for :first_name, :logic => lambda { first_name == 'Jamie' }
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# The logic option is required.
|
184
|
+
#
|
185
|
+
# Configuration options:
|
186
|
+
#
|
187
|
+
# * after_validate - A block that executes following the run of a validation
|
188
|
+
# * message - The message to add to the errors collection when the validation fails
|
189
|
+
# * times - The number of times the validation applies
|
190
|
+
# * level - The level at which the validation should occur
|
191
|
+
# * if - A block that when executed must return true of the validation will not occur
|
192
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
193
|
+
# * logic - A block that executes to perform the validation
|
194
|
+
def validates_true_for(*args)
|
195
|
+
add_validations(args, ValidatesTrueFor)
|
196
|
+
end
|
197
|
+
|
198
|
+
def validates_exclusion_of(*args)
|
199
|
+
add_validations(args, ValidatesExclusionOf)
|
200
|
+
end
|
201
|
+
|
202
|
+
def validates_inclusion_of(*args)
|
203
|
+
add_validations(args, ValidatesInclusionOf)
|
204
|
+
end
|
205
|
+
|
206
|
+
# call-seq: validates_associated(*args)
|
207
|
+
#
|
208
|
+
# Checks the validity of an associated object or objects and adds a single
|
209
|
+
# error if validation fails.
|
210
|
+
#
|
211
|
+
# class Person
|
212
|
+
# include Validatable
|
213
|
+
# attr_accessor :addresses
|
214
|
+
# validates_associated :addresses
|
215
|
+
# end
|
216
|
+
#
|
217
|
+
# Configuration options:
|
218
|
+
#
|
219
|
+
# * after_validate - A block that executes following the run of a validation
|
220
|
+
# * message - The message to add to the errors collection when the validation fails
|
221
|
+
# * times - The number of times the validation applies
|
222
|
+
# * level - The level at which the validation should occur
|
223
|
+
# * if - A block that when executed must return true of the validation will not occur
|
224
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
225
|
+
def validates_associated(*args)
|
226
|
+
add_validations(args, ValidatesAssociated)
|
227
|
+
end
|
228
|
+
|
229
|
+
# call-seq: include_validations_from(attribute)
|
230
|
+
#
|
231
|
+
# Includes all the validations that are defined on the attribute.
|
232
|
+
# class Person
|
233
|
+
# include Validatable
|
234
|
+
# validates_presence_of :name
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# class PersonPresenter
|
238
|
+
# include Validatable
|
239
|
+
# include_validataions_from :person
|
240
|
+
# attr_accessor :person
|
241
|
+
# def name
|
242
|
+
# person.name
|
243
|
+
# end
|
244
|
+
#
|
245
|
+
# def initialize(person)
|
246
|
+
# @person = person
|
247
|
+
# end
|
248
|
+
# end
|
249
|
+
#
|
250
|
+
# presenter = PersonPresenter.new(Person.new)
|
251
|
+
# presenter.valid? #=> false
|
252
|
+
# presenter.errors.on(:name) #=> "can't be blank"
|
253
|
+
#
|
254
|
+
# The name attribute whose validations should be added.
|
255
|
+
def include_validations_from(attribute_to_validate, options = {})
|
256
|
+
validations_to_include << IncludedValidation.new(attribute_to_validate)
|
257
|
+
end
|
258
|
+
|
259
|
+
# call-seq: include_errors_from(attribute_to_validate, options = {})
|
260
|
+
#
|
261
|
+
# Validates the specified attributes.
|
262
|
+
# class Person
|
263
|
+
# include Validatable
|
264
|
+
# validates_presence_of :name
|
265
|
+
# attr_accessor :name
|
266
|
+
# end
|
267
|
+
#
|
268
|
+
# class PersonPresenter
|
269
|
+
# include Validatable
|
270
|
+
# include_errors_from :person, :map => { :name => :namen }, :if => lambda { not person.nil? }
|
271
|
+
# attr_accessor :person
|
272
|
+
#
|
273
|
+
# def initialize(person)
|
274
|
+
# @person = person
|
275
|
+
# end
|
276
|
+
# end
|
277
|
+
#
|
278
|
+
# presenter = PersonPresenter.new(Person.new)
|
279
|
+
# presenter.valid? #=> false
|
280
|
+
# presenter.errors.on(:namen) #=> "can't be blank"
|
281
|
+
#
|
282
|
+
# The person attribute will be validated.
|
283
|
+
# If person is invalid the errors will be added to the PersonPresenter errors collection.
|
284
|
+
#
|
285
|
+
# Configuration options:
|
286
|
+
#
|
287
|
+
# * map - A hash that maps attributes of the child to attributes of the parent.
|
288
|
+
# * if - A block that when executed must return true of the validation will not occur.
|
289
|
+
def include_errors_from(attribute_to_validate, options = {})
|
290
|
+
children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
|
291
|
+
end
|
292
|
+
|
293
|
+
def include_validations_for(attribute_to_validate, options = {}) #:nodoc:
|
294
|
+
puts "include_validations_for is deprecated; use include_errors_from instead"
|
295
|
+
children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
|
296
|
+
end
|
297
|
+
|
298
|
+
# call-seq: before_validation(&block)
|
299
|
+
#
|
300
|
+
# Is called before valid? or valid_for_*?
|
301
|
+
#
|
302
|
+
# class Person
|
303
|
+
# include Validatable
|
304
|
+
# before_validation do
|
305
|
+
# self.name = "default name"
|
306
|
+
# end
|
307
|
+
#
|
308
|
+
# attr_accessor :name
|
309
|
+
# end
|
310
|
+
#
|
311
|
+
def before_validation(&block)
|
312
|
+
before_validations << block
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|