mongo_mapper 0.12.0 → 0.13.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.rdoc +35 -13
- data/bin/mmconsole +1 -1
- data/lib/mongo_mapper.rb +4 -0
- data/lib/mongo_mapper/connection.rb +17 -6
- data/lib/mongo_mapper/document.rb +1 -0
- data/lib/mongo_mapper/exceptions.rb +4 -1
- data/lib/mongo_mapper/extensions/binary.rb +1 -1
- data/lib/mongo_mapper/extensions/boolean.rb +20 -23
- data/lib/mongo_mapper/extensions/date.rb +3 -3
- data/lib/mongo_mapper/extensions/integer.rb +5 -1
- data/lib/mongo_mapper/extensions/kernel.rb +2 -0
- data/lib/mongo_mapper/extensions/ordered_hash.rb +23 -0
- data/lib/mongo_mapper/extensions/string.rb +2 -2
- data/lib/mongo_mapper/extensions/time.rb +7 -5
- data/lib/mongo_mapper/middleware/identity_map.rb +3 -4
- data/lib/mongo_mapper/plugins.rb +1 -1
- data/lib/mongo_mapper/plugins/associations.rb +11 -5
- data/lib/mongo_mapper/plugins/associations/base.rb +5 -3
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +0 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +8 -8
- data/lib/mongo_mapper/plugins/associations/collection.rb +2 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +32 -7
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +2 -2
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +12 -12
- data/lib/mongo_mapper/plugins/associations/proxy.rb +5 -1
- data/lib/mongo_mapper/plugins/associations/single_association.rb +6 -6
- data/lib/mongo_mapper/plugins/clone.rb +4 -2
- data/lib/mongo_mapper/plugins/dirty.rb +22 -21
- data/lib/mongo_mapper/plugins/document.rb +4 -4
- data/lib/mongo_mapper/plugins/dumpable.rb +22 -0
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +58 -9
- data/lib/mongo_mapper/plugins/identity_map.rb +42 -32
- data/lib/mongo_mapper/plugins/keys.rb +133 -54
- data/lib/mongo_mapper/plugins/keys/key.rb +68 -22
- data/lib/mongo_mapper/plugins/modifiers.rb +26 -19
- data/lib/mongo_mapper/plugins/persistence.rb +15 -5
- data/lib/mongo_mapper/plugins/querying.rb +15 -40
- data/lib/mongo_mapper/plugins/querying/{decorator.rb → decorated_plucky_query.rb} +24 -4
- data/lib/mongo_mapper/plugins/rails.rb +22 -2
- data/lib/mongo_mapper/plugins/safe.rb +8 -5
- data/lib/mongo_mapper/plugins/sci.rb +26 -4
- data/lib/mongo_mapper/plugins/scopes.rb +5 -4
- data/lib/mongo_mapper/plugins/timestamps.rb +11 -4
- data/lib/mongo_mapper/plugins/validations.rb +1 -1
- data/lib/mongo_mapper/utils.rb +12 -0
- data/lib/mongo_mapper/version.rb +1 -1
- data/lib/rails/generators/mongo_mapper/config/config_generator.rb +20 -7
- data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +6 -0
- data/lib/rails/generators/mongo_mapper/model/model_generator.rb +18 -1
- data/lib/rails/generators/mongo_mapper/model/templates/model.rb +9 -5
- data/{test/functional/test_accessible.rb → spec/functional/accessible_spec.rb} +29 -29
- data/{test/functional/associations/test_belongs_to_polymorphic_proxy.rb → spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb} +10 -10
- data/{test/functional/associations/test_belongs_to_proxy.rb → spec/functional/associations/belongs_to_proxy_spec.rb} +82 -64
- data/{test/functional/associations/test_in_array_proxy.rb → spec/functional/associations/in_array_proxy_spec.rb} +68 -68
- data/{test/functional/associations/test_many_documents_as_proxy.rb → spec/functional/associations/many_documents_as_proxy_spec.rb} +37 -38
- data/{test/functional/associations/test_many_documents_proxy.rb → spec/functional/associations/many_documents_proxy_spec.rb} +233 -146
- data/{test/functional/associations/test_many_embedded_polymorphic_proxy.rb → spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb} +19 -20
- data/{test/functional/associations/test_many_embedded_proxy.rb → spec/functional/associations/many_embedded_proxy_spec.rb} +23 -24
- data/{test/functional/associations/test_many_polymorphic_proxy.rb → spec/functional/associations/many_polymorphic_proxy_spec.rb} +45 -46
- data/{test/functional/associations/test_one_as_proxy.rb → spec/functional/associations/one_as_proxy_spec.rb} +75 -77
- data/{test/functional/associations/test_one_embedded_polymorphic_proxy.rb → spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb} +31 -32
- data/{test/functional/associations/test_one_embedded_proxy.rb → spec/functional/associations/one_embedded_proxy_spec.rb} +10 -10
- data/{test/functional/associations/test_one_proxy.rb → spec/functional/associations/one_proxy_spec.rb} +125 -102
- data/spec/functional/associations_spec.rb +48 -0
- data/{test/functional/test_binary.rb → spec/functional/binary_spec.rb} +6 -6
- data/spec/functional/caching_spec.rb +75 -0
- data/{test/functional/test_callbacks.rb → spec/functional/callbacks_spec.rb} +84 -26
- data/{test/functional/test_dirty.rb → spec/functional/dirty_spec.rb} +57 -42
- data/{test/functional/test_document.rb → spec/functional/document_spec.rb} +52 -52
- data/spec/functional/dumpable_spec.rb +24 -0
- data/{test/functional/test_dynamic_querying.rb → spec/functional/dynamic_querying_spec.rb} +14 -14
- data/{test/functional/test_embedded_document.rb → spec/functional/embedded_document_spec.rb} +51 -42
- data/{test/functional/test_equality.rb → spec/functional/equality_spec.rb} +4 -4
- data/spec/functional/extensions_spec.rb +16 -0
- data/{test/functional/test_identity_map.rb → spec/functional/identity_map_spec.rb} +73 -61
- data/spec/functional/indexes_spec.rb +48 -0
- data/spec/functional/keys_spec.rb +224 -0
- data/{test/functional/test_logger.rb → spec/functional/logger_spec.rb} +6 -6
- data/spec/functional/modifiers_spec.rb +550 -0
- data/spec/functional/pagination_spec.rb +89 -0
- data/spec/functional/protected_spec.rb +199 -0
- data/spec/functional/querying_spec.rb +1003 -0
- data/spec/functional/rails_spec.rb +55 -0
- data/spec/functional/safe_spec.rb +163 -0
- data/{test/functional/test_sci.rb → spec/functional/sci_spec.rb} +123 -34
- data/{test/functional/test_scopes.rb → spec/functional/scopes_spec.rb} +59 -26
- data/spec/functional/timestamps_spec.rb +97 -0
- data/{test/functional/test_touch.rb → spec/functional/touch_spec.rb} +13 -13
- data/spec/functional/userstamps_spec.rb +46 -0
- data/{test/functional/test_validations.rb → spec/functional/validations_spec.rb} +64 -64
- data/spec/spec_helper.rb +81 -0
- data/spec/support/matchers.rb +24 -0
- data/{test → spec/support}/models.rb +1 -6
- data/spec/unit/associations/base_spec.rb +146 -0
- data/spec/unit/associations/belongs_to_association_spec.rb +30 -0
- data/spec/unit/associations/many_association_spec.rb +64 -0
- data/spec/unit/associations/one_association_spec.rb +48 -0
- data/{test/unit/associations/test_proxy.rb → spec/unit/associations/proxy_spec.rb} +21 -21
- data/{test/unit/test_clone.rb → spec/unit/clone_spec.rb} +21 -11
- data/spec/unit/config_generator_spec.rb +24 -0
- data/{test/unit/test_document.rb → spec/unit/document_spec.rb} +42 -42
- data/{test/unit/test_dynamic_finder.rb → spec/unit/dynamic_finder_spec.rb} +28 -28
- data/{test/unit/test_embedded_document.rb → spec/unit/embedded_document_spec.rb} +102 -108
- data/{test/unit/test_equality.rb → spec/unit/equality_spec.rb} +7 -7
- data/{test/unit/test_exceptions.rb → spec/unit/exceptions_spec.rb} +3 -3
- data/{test/unit/test_extensions.rb → spec/unit/extensions_spec.rb} +85 -71
- data/spec/unit/identity_map_middleware_spec.rb +134 -0
- data/{test/unit/test_inspect.rb → spec/unit/inspect_spec.rb} +8 -8
- data/{test/unit/test_key.rb → spec/unit/key_spec.rb} +82 -52
- data/spec/unit/keys_spec.rb +155 -0
- data/spec/unit/model_generator_spec.rb +47 -0
- data/spec/unit/mongo_mapper_spec.rb +184 -0
- data/spec/unit/pagination_spec.rb +11 -0
- data/{test/unit/test_plugins.rb → spec/unit/plugins_spec.rb} +14 -14
- data/spec/unit/rails_compatibility_spec.rb +40 -0
- data/{test/unit/test_rails_reflect_on_association.rb → spec/unit/rails_reflect_on_association_spec.rb} +9 -9
- data/{test/unit/test_rails.rb → spec/unit/rails_spec.rb} +31 -31
- data/spec/unit/serialization_spec.rb +169 -0
- data/spec/unit/serializers/json_serializer_spec.rb +218 -0
- data/spec/unit/serializers/xml_serializer_spec.rb +198 -0
- data/{test/unit/test_time_zones.rb → spec/unit/time_zones_spec.rb} +8 -8
- data/{test/unit/test_translation.rb → spec/unit/translation_spec.rb} +6 -6
- data/{test/unit/test_validations.rb → spec/unit/validations_spec.rb} +72 -59
- metadata +199 -179
- data/test/_NOTE_ON_TESTING +0 -1
- data/test/functional/test_associations.rb +0 -46
- data/test/functional/test_caching.rb +0 -77
- data/test/functional/test_indexes.rb +0 -50
- data/test/functional/test_modifiers.rb +0 -537
- data/test/functional/test_pagination.rb +0 -91
- data/test/functional/test_protected.rb +0 -201
- data/test/functional/test_querying.rb +0 -935
- data/test/functional/test_safe.rb +0 -76
- data/test/functional/test_timestamps.rb +0 -62
- data/test/functional/test_userstamps.rb +0 -44
- data/test/support/railtie.rb +0 -4
- data/test/support/railtie/autoloaded.rb +0 -2
- data/test/support/railtie/not_autoloaded.rb +0 -3
- data/test/support/railtie/parent.rb +0 -3
- data/test/test_active_model_lint.rb +0 -18
- data/test/test_helper.rb +0 -93
- data/test/unit/associations/test_base.rb +0 -146
- data/test/unit/associations/test_belongs_to_association.rb +0 -29
- data/test/unit/associations/test_many_association.rb +0 -63
- data/test/unit/associations/test_one_association.rb +0 -47
- data/test/unit/serializers/test_json_serializer.rb +0 -216
- data/test/unit/serializers/test_xml_serializer.rb +0 -196
- data/test/unit/test_identity_map_middleware.rb +0 -132
- data/test/unit/test_keys.rb +0 -65
- data/test/unit/test_mongo_mapper.rb +0 -157
- data/test/unit/test_pagination.rb +0 -11
- data/test/unit/test_rails_compatibility.rb +0 -38
- data/test/unit/test_serialization.rb +0 -166
@@ -1,8 +1,8 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
|
-
|
3
|
+
describe "Scopes" do
|
4
4
|
context "Scopes" do
|
5
|
-
|
5
|
+
before do
|
6
6
|
@document = Doc() do
|
7
7
|
key :name, String
|
8
8
|
key :age, Integer
|
@@ -11,33 +11,58 @@ class ScopesTest < Test::Unit::TestCase
|
|
11
11
|
end
|
12
12
|
|
13
13
|
context "basic scopes" do
|
14
|
-
|
14
|
+
before do
|
15
15
|
@document.class_eval do
|
16
16
|
scope :old, :age.gt => 60
|
17
17
|
scope :teens, :age.gte => 13, :age.lte => 19
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
should
|
21
|
+
it "should know what scopes have been added" do
|
22
22
|
@document.scopes.size.should == 2
|
23
23
|
@document.scopes.keys.map(&:to_s).sort.should == %w(old teens)
|
24
24
|
end
|
25
25
|
|
26
|
-
should
|
27
|
-
@document.old.should
|
26
|
+
it "should return a plucky query" do
|
27
|
+
@document.old.should be_kind_of(Plucky::Query)
|
28
28
|
end
|
29
29
|
|
30
|
-
should
|
30
|
+
it "should work" do
|
31
31
|
@document.create(:name => 'John', :age => 99)
|
32
32
|
@document.create(:name => 'Frank', :age => 15)
|
33
33
|
docs = @document.old.all
|
34
34
|
docs.size.should == 1
|
35
35
|
docs[0].name.should == 'John'
|
36
36
|
end
|
37
|
+
|
38
|
+
# Regression test for #534
|
39
|
+
context "when where() is invoked via a scope before a key is defined" do
|
40
|
+
let(:given_id) { BSON::ObjectId.new }
|
41
|
+
let(:doc) { Doc {
|
42
|
+
key :type, String
|
43
|
+
|
44
|
+
# Ordering is important here; where needs to happen before foo_id is defined
|
45
|
+
# in order to produce the behavior we're testing against regression.
|
46
|
+
scope :type, where(type: "bar")
|
47
|
+
key :foo_id, ObjectId
|
48
|
+
}}
|
49
|
+
before {
|
50
|
+
doc.collection.drop
|
51
|
+
doc.create({:foo_id => given_id})
|
52
|
+
}
|
53
|
+
|
54
|
+
it "should work without typecasts" do
|
55
|
+
doc.where(:foo_id => given_id).count.should == 1
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should work with typecasts" do
|
59
|
+
doc.where(:foo_id => given_id.to_s).count.should == 1
|
60
|
+
end
|
61
|
+
end
|
37
62
|
end
|
38
63
|
|
39
64
|
context "dynamic scopes" do
|
40
|
-
|
65
|
+
before do
|
41
66
|
@document.class_eval do
|
42
67
|
scope :age, lambda { |age| {:age => age} }
|
43
68
|
scope :ages, lambda { |low, high| {:age.gte => low, :age.lte => high} }
|
@@ -45,7 +70,7 @@ class ScopesTest < Test::Unit::TestCase
|
|
45
70
|
end
|
46
71
|
end
|
47
72
|
|
48
|
-
should
|
73
|
+
it "should work with single argument" do
|
49
74
|
@document.create(:name => 'John', :age => 60)
|
50
75
|
@document.create(:name => 'Frank', :age => 50)
|
51
76
|
docs = @document.age(60).all
|
@@ -53,7 +78,7 @@ class ScopesTest < Test::Unit::TestCase
|
|
53
78
|
docs.first.name.should == 'John'
|
54
79
|
end
|
55
80
|
|
56
|
-
should
|
81
|
+
it "should work with multiple arguments" do
|
57
82
|
@document.create(:name => 'John', :age => 60)
|
58
83
|
@document.create(:name => 'Frank', :age => 50)
|
59
84
|
@document.create(:name => 'Bill', :age => 40)
|
@@ -62,7 +87,7 @@ class ScopesTest < Test::Unit::TestCase
|
|
62
87
|
docs.map(&:name).sort.should == %w(Frank John)
|
63
88
|
end
|
64
89
|
|
65
|
-
should
|
90
|
+
it "should work with queries" do
|
66
91
|
john = @document.create(:name => 'John', :age => 60)
|
67
92
|
frank = @document.create(:name => 'Frank', :age => 50)
|
68
93
|
bill = @document.create(:name => 'Bill', :age => 40)
|
@@ -71,13 +96,13 @@ class ScopesTest < Test::Unit::TestCase
|
|
71
96
|
end
|
72
97
|
|
73
98
|
context "query scopes" do
|
74
|
-
|
99
|
+
before do
|
75
100
|
@document.class_eval do
|
76
101
|
scope :boomers, where(:age.gte => 60).sort(:age)
|
77
102
|
end
|
78
103
|
end
|
79
104
|
|
80
|
-
should
|
105
|
+
it "should work" do
|
81
106
|
todd = @document.create(:name => 'Todd', :age => 65)
|
82
107
|
john = @document.create(:name => 'John', :age => 60)
|
83
108
|
@document.create(:name => 'Frank', :age => 50)
|
@@ -89,14 +114,14 @@ class ScopesTest < Test::Unit::TestCase
|
|
89
114
|
end
|
90
115
|
|
91
116
|
context "chaining" do
|
92
|
-
|
117
|
+
before do
|
93
118
|
@document.class_eval do
|
94
119
|
scope :by_age, lambda { |age| {:age => age} }
|
95
120
|
scope :by_name, lambda { |name| {:name => name} }
|
96
121
|
end
|
97
122
|
end
|
98
123
|
|
99
|
-
should
|
124
|
+
it "should work with scope methods" do
|
100
125
|
@document.create(:name => 'John', :age => 60)
|
101
126
|
@document.create(:name => 'Frank', :age => 60)
|
102
127
|
@document.create(:name => 'Bill', :age => 50)
|
@@ -105,7 +130,7 @@ class ScopesTest < Test::Unit::TestCase
|
|
105
130
|
docs.first.name.should == 'John'
|
106
131
|
end
|
107
132
|
|
108
|
-
should
|
133
|
+
it "should work on query methods" do
|
109
134
|
@document.create(:name => 'John', :age => 60)
|
110
135
|
@document.create(:name => 'John', :age => 50)
|
111
136
|
@document.create(:name => 'Bill', :age => 50)
|
@@ -115,7 +140,7 @@ class ScopesTest < Test::Unit::TestCase
|
|
115
140
|
end
|
116
141
|
|
117
142
|
context "with model methods" do
|
118
|
-
should
|
143
|
+
it "should work if method returns a query" do
|
119
144
|
@document.create(:name => 'John', :age => 10)
|
120
145
|
@document.create(:name => 'John', :age => 20)
|
121
146
|
@document.class_eval do
|
@@ -128,15 +153,15 @@ class ScopesTest < Test::Unit::TestCase
|
|
128
153
|
docs.first.age.should == 10
|
129
154
|
end
|
130
155
|
|
131
|
-
should
|
156
|
+
it "should not work if method does not return a query" do
|
132
157
|
@document.class_eval { def self.age; 20 end }
|
133
|
-
|
158
|
+
@document.by_name('John').age.should == 20
|
134
159
|
end
|
135
160
|
end
|
136
161
|
end
|
137
162
|
|
138
163
|
context "with single collection inheritance" do
|
139
|
-
|
164
|
+
before do
|
140
165
|
class ::Item
|
141
166
|
include MongoMapper::Document
|
142
167
|
scope :by_title, lambda { |title| {:title => title} }
|
@@ -148,24 +173,32 @@ class ScopesTest < Test::Unit::TestCase
|
|
148
173
|
Item.collection.remove
|
149
174
|
|
150
175
|
class ::Page < ::Item; end
|
151
|
-
class ::Blog < ::Item
|
176
|
+
class ::Blog < ::Item
|
177
|
+
key :slug, String
|
178
|
+
scope :by_slug, lambda { |slug| {:slug => slug} }
|
179
|
+
end
|
152
180
|
end
|
153
181
|
|
154
|
-
|
182
|
+
after do
|
155
183
|
Object.send :remove_const, 'Item' if defined?(::Item)
|
156
184
|
Object.send :remove_const, 'Page' if defined?(::Page)
|
157
185
|
Object.send :remove_const, 'Blog' if defined?(::Blog)
|
158
186
|
end
|
159
187
|
|
160
|
-
should
|
188
|
+
it "should inherit scopes" do
|
161
189
|
Page.scopes.keys.map(&:to_s).sort.should == %w(by_title published)
|
162
190
|
end
|
163
191
|
|
164
|
-
should
|
192
|
+
it "should work with _type" do
|
165
193
|
item = Item.create(:title => 'Home')
|
166
194
|
page = Page.create(:title => 'Home')
|
167
195
|
Page.by_title('Home').first.should == page
|
168
196
|
end
|
197
|
+
|
198
|
+
it "should limit subclass scopes to subclasses" do
|
199
|
+
Item.scopes.keys.map(&:to_s).should =~ %w(by_title published)
|
200
|
+
Blog.scopes.keys.map(&:to_s).should =~ %w(by_slug by_title published)
|
201
|
+
end
|
169
202
|
end
|
170
203
|
end
|
171
|
-
end
|
204
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Timestamps" do
|
4
|
+
context "included" do
|
5
|
+
before do
|
6
|
+
@klass = Doc do
|
7
|
+
key :first_name, String
|
8
|
+
end
|
9
|
+
@klass.timestamps!
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should set record_timestamps to true" do
|
13
|
+
@klass.record_timestamps.should be(true)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "timestamping" do
|
18
|
+
before do
|
19
|
+
@klass = Doc do
|
20
|
+
key :first_name, String
|
21
|
+
key :last_name, String
|
22
|
+
key :age, Integer
|
23
|
+
key :date, Date
|
24
|
+
end
|
25
|
+
@klass.timestamps!
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when #record_timestamps is set to true" do
|
29
|
+
it "should set created_at and updated_at on create" do
|
30
|
+
doc = @klass.new(:first_name => 'John', :age => 27)
|
31
|
+
doc.created_at.should be(nil)
|
32
|
+
doc.updated_at.should be(nil)
|
33
|
+
doc.save
|
34
|
+
doc.created_at.should_not be(nil)
|
35
|
+
doc.updated_at.should_not be(nil)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not overwrite created_at if it already exists" do
|
39
|
+
original_created_at = 1.month.ago
|
40
|
+
doc = @klass.new(:first_name => 'John', :age => 27, :created_at => original_created_at)
|
41
|
+
doc.created_at.to_i.should == original_created_at.to_i
|
42
|
+
doc.updated_at.should be_nil
|
43
|
+
doc.save
|
44
|
+
doc.created_at.to_i.should == original_created_at.to_i
|
45
|
+
doc.updated_at.should_not be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should set updated_at on field update but leave created_at alone" do
|
49
|
+
doc = @klass.create(:first_name => 'John', :age => 27)
|
50
|
+
old_created_at = doc.created_at
|
51
|
+
old_updated_at = doc.updated_at
|
52
|
+
doc.first_name = 'Johnny'
|
53
|
+
|
54
|
+
Timecop.freeze(Time.now + 5.seconds) do
|
55
|
+
doc.save
|
56
|
+
end
|
57
|
+
|
58
|
+
doc.created_at.should == old_created_at
|
59
|
+
doc.updated_at.should_not == old_updated_at
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should set updated_at on document update but leave created_at alone" do
|
63
|
+
doc = @klass.create(:first_name => 'John', :age => 27)
|
64
|
+
old_created_at = doc.created_at.to_i
|
65
|
+
|
66
|
+
new_updated_at = Time.at(Time.now.to_i + 5.seconds)
|
67
|
+
Timecop.freeze(new_updated_at) do
|
68
|
+
@klass.update(doc._id, { :first_name => 'Johnny' })
|
69
|
+
end
|
70
|
+
|
71
|
+
doc = doc.reload
|
72
|
+
doc.created_at.to_i.should be_within(1).of(old_created_at.to_i)
|
73
|
+
doc.updated_at.to_i.should be_within(1).of(new_updated_at.to_i)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "when #record_timestamps is set to false" do
|
78
|
+
before do
|
79
|
+
@klass.record_timestamps = false
|
80
|
+
end
|
81
|
+
|
82
|
+
after do
|
83
|
+
@klass.record_timestamps = true
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should not set created_at on document create" do
|
87
|
+
doc = @klass.create(:first_name => "John")
|
88
|
+
doc.created_at.should be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should not set updated_at on document create" do
|
92
|
+
doc = @klass.create(:first_name => "John")
|
93
|
+
doc.updated_at.should be_nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
|
-
|
3
|
+
describe "Touch" do
|
4
4
|
context "touch" do
|
5
5
|
context "document" do
|
6
|
-
|
6
|
+
before do
|
7
7
|
@document = Doc { timestamps! }
|
8
8
|
end
|
9
9
|
|
10
|
-
should
|
10
|
+
it "should update the updated_at timestamp" do
|
11
11
|
doc = @document.create
|
12
12
|
old_updated_at = doc.updated_at
|
13
13
|
|
@@ -21,7 +21,7 @@ class TouchTest < Test::Unit::TestCase
|
|
21
21
|
end
|
22
22
|
|
23
23
|
context "embedded document" do
|
24
|
-
should
|
24
|
+
it "should update the updated_at timestamp" do
|
25
25
|
Doc = Doc("Document") { timestamps!}
|
26
26
|
Emdoc = EDoc("EmbeddedDocument") { timestamps! }
|
27
27
|
Doc.has_many :emdocs, :class => Emdoc
|
@@ -45,7 +45,7 @@ class TouchTest < Test::Unit::TestCase
|
|
45
45
|
end
|
46
46
|
|
47
47
|
context "association" do
|
48
|
-
|
48
|
+
before do
|
49
49
|
@post_class = Doc("Post") do
|
50
50
|
key :touched_at, DateTime
|
51
51
|
timestamps!
|
@@ -59,19 +59,19 @@ class TouchTest < Test::Unit::TestCase
|
|
59
59
|
@post_class.many :comments, :class => @comment_class
|
60
60
|
end
|
61
61
|
|
62
|
-
should
|
62
|
+
it 'should not be true by default' do
|
63
63
|
@comment_class.belongs_to :post, :class => @post_class
|
64
64
|
@comment_class.associations[:post].touch?.should_not be_true
|
65
65
|
end
|
66
66
|
|
67
67
|
context 'touch the parent when true' do
|
68
|
-
|
68
|
+
before do
|
69
69
|
@comment_class.belongs_to :post, :class => @post_class, :touch => true
|
70
70
|
@post = @post_class.create(:title => 'Hello, world!')
|
71
71
|
@comment = @post.comments.build
|
72
72
|
end
|
73
73
|
|
74
|
-
should
|
74
|
+
it "should when the child is created" do
|
75
75
|
orig_updated_at = @post.updated_at
|
76
76
|
Timecop.freeze(Time.now + 1.day) do
|
77
77
|
@comment.save
|
@@ -80,7 +80,7 @@ class TouchTest < Test::Unit::TestCase
|
|
80
80
|
@post.reload.updated_at.should_not == orig_updated_at
|
81
81
|
end
|
82
82
|
|
83
|
-
should
|
83
|
+
it "should when the child is updated" do
|
84
84
|
@comment.save
|
85
85
|
old_updated_at = @post.updated_at
|
86
86
|
Timecop.freeze(Time.now + 2.day) do
|
@@ -89,7 +89,7 @@ class TouchTest < Test::Unit::TestCase
|
|
89
89
|
@post.reload.updated_at.should_not == old_updated_at
|
90
90
|
end
|
91
91
|
|
92
|
-
should
|
92
|
+
it "should when the child is touched" do
|
93
93
|
@comment.save
|
94
94
|
old_updated_at = @post.updated_at
|
95
95
|
Timecop.freeze(Time.now + 3.day) do
|
@@ -100,7 +100,7 @@ class TouchTest < Test::Unit::TestCase
|
|
100
100
|
end
|
101
101
|
|
102
102
|
context "when set to a symbol that is a key of parent" do
|
103
|
-
should
|
103
|
+
it "should set that key on touch events" do
|
104
104
|
@comment_class.belongs_to :post, :class => @post_class, :touch => :touched_at
|
105
105
|
post = @post_class.create(:title => 'Hello, world!')
|
106
106
|
post.touched_at.should be_nil
|
@@ -111,7 +111,7 @@ class TouchTest < Test::Unit::TestCase
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
should
|
114
|
+
it 'should not touch the parent when false' do
|
115
115
|
post = @post_class.create(:title => 'Hello, world!')
|
116
116
|
comment = post.comments.build
|
117
117
|
Timecop.freeze(Time.now + 1.day) do
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Userstamps
|
4
|
+
describe "Userstamps" do
|
5
|
+
class AltUser
|
6
|
+
include MongoMapper::Document
|
7
|
+
end
|
8
|
+
|
9
|
+
context "userstamping" do
|
10
|
+
before do
|
11
|
+
@document = Doc do
|
12
|
+
userstamps!
|
13
|
+
end
|
14
|
+
@document_alt_user = Doc do
|
15
|
+
userstamps! :class_name => 'Userstamps::AltUser'
|
16
|
+
end
|
17
|
+
@document_alt_user_class = Doc do
|
18
|
+
userstamps! :class => Userstamps::AltUser
|
19
|
+
end
|
20
|
+
@docs = [@document, @document_alt_user, @document_alt_user_class]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should add creator_id key" do
|
24
|
+
@docs.each{ |d| d.keys.should include('creator_id') }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should add updater_id key" do
|
28
|
+
@docs.each{ |d| d.keys.should include('updater_id') }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should add belongs_to creator" do
|
32
|
+
@docs.each{ |d| d.associations.keys.should include(:creator) }
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should add belongs_to updater" do
|
36
|
+
@docs.each{ |d| d.associations.keys.should include(:updater) }
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should properly set class names" do
|
40
|
+
@document.associations[:creator].class_name.should == 'User'
|
41
|
+
@document_alt_user.associations[:creator].class_name.should == 'Userstamps::AltUser'
|
42
|
+
@document_alt_user_class.associations[:creator].class_name.should == 'Userstamps::AltUser'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,20 +1,20 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
|
-
|
3
|
+
describe "Validations" do
|
4
4
|
context "Saving a new document that is invalid" do
|
5
|
-
|
5
|
+
before do
|
6
6
|
@document = Doc do
|
7
7
|
key :name, String, :required => true
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
should
|
11
|
+
it "should not insert document" do
|
12
12
|
doc = @document.new
|
13
13
|
doc.save
|
14
14
|
@document.count.should == 0
|
15
15
|
end
|
16
16
|
|
17
|
-
should
|
17
|
+
it "should populate document's errors" do
|
18
18
|
doc = @document.new
|
19
19
|
doc.errors.size.should == 0
|
20
20
|
doc.save
|
@@ -23,18 +23,18 @@ class ValidationsTest < Test::Unit::TestCase
|
|
23
23
|
end
|
24
24
|
|
25
25
|
context "Saving a document that is invalid (destructive)" do
|
26
|
-
|
26
|
+
before do
|
27
27
|
@document = Doc do
|
28
28
|
key :name, String, :required => true
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
should
|
32
|
+
it "should raise error" do
|
33
33
|
doc = @document.new
|
34
34
|
lambda { doc.save! }.should raise_error(MongoMapper::DocumentNotValid)
|
35
35
|
end
|
36
36
|
|
37
|
-
should
|
37
|
+
it "should set document on exception" do
|
38
38
|
doc = @document.new
|
39
39
|
begin
|
40
40
|
doc.save!
|
@@ -45,24 +45,24 @@ class ValidationsTest < Test::Unit::TestCase
|
|
45
45
|
end
|
46
46
|
|
47
47
|
context "Creating a document that is invalid (destructive)" do
|
48
|
-
|
48
|
+
before do
|
49
49
|
@document = Doc do
|
50
50
|
key :name, String, :required => true
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
should
|
54
|
+
it "should raise error" do
|
55
55
|
lambda { @document.create! }.should raise_error(MongoMapper::DocumentNotValid)
|
56
56
|
end
|
57
57
|
|
58
|
-
should
|
58
|
+
it "should create a new document" do
|
59
59
|
instance = @document.create!(:name => "James")
|
60
60
|
instance.new_record?.should be_false
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
64
|
context "Saving an existing document that is invalid" do
|
65
|
-
|
65
|
+
before do
|
66
66
|
@document = Doc do
|
67
67
|
key :name, String, :required => true
|
68
68
|
end
|
@@ -70,13 +70,13 @@ class ValidationsTest < Test::Unit::TestCase
|
|
70
70
|
@doc = @document.create(:name => 'John Nunemaker')
|
71
71
|
end
|
72
72
|
|
73
|
-
should
|
73
|
+
it "should not update document" do
|
74
74
|
@doc.name = nil
|
75
75
|
@doc.save
|
76
76
|
@doc.reload.name.should == 'John Nunemaker'
|
77
77
|
end
|
78
78
|
|
79
|
-
should
|
79
|
+
it "should populate document's errors" do
|
80
80
|
@doc.name = nil
|
81
81
|
@doc.save
|
82
82
|
@doc.errors.full_messages.should == ["Name can't be blank"]
|
@@ -84,7 +84,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
84
84
|
end
|
85
85
|
|
86
86
|
context "Adding validation errors" do
|
87
|
-
|
87
|
+
before do
|
88
88
|
@document = Doc do
|
89
89
|
key :action, String
|
90
90
|
def action_present
|
@@ -93,7 +93,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
should
|
96
|
+
it "should work with validate :on => :create callback" do
|
97
97
|
@document.validate :action_present, :on => :create
|
98
98
|
|
99
99
|
doc = @document.create(:action => nil)
|
@@ -104,7 +104,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
104
104
|
doc.should_not have_error_on(:action)
|
105
105
|
end
|
106
106
|
|
107
|
-
should
|
107
|
+
it "should work with validate :on => :update callback" do
|
108
108
|
@document.validate :action_present, :on => :update
|
109
109
|
|
110
110
|
doc = @document.new
|
@@ -121,19 +121,19 @@ class ValidationsTest < Test::Unit::TestCase
|
|
121
121
|
end
|
122
122
|
|
123
123
|
context "validating uniqueness of" do
|
124
|
-
|
124
|
+
before do
|
125
125
|
@document = Doc do
|
126
126
|
key :name, String
|
127
127
|
validates_uniqueness_of :name
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
|
-
should
|
131
|
+
it "should not fail if object is new" do
|
132
132
|
doc = @document.new
|
133
133
|
doc.should_not have_error_on(:name)
|
134
134
|
end
|
135
135
|
|
136
|
-
should
|
136
|
+
it "should not fail when new object is out of scope" do
|
137
137
|
document = Doc do
|
138
138
|
key :name
|
139
139
|
key :adult
|
@@ -146,40 +146,40 @@ class ValidationsTest < Test::Unit::TestCase
|
|
146
146
|
doc2.should be_valid
|
147
147
|
end
|
148
148
|
|
149
|
-
should
|
149
|
+
it "should work with i18n taken message" do
|
150
150
|
@document.create(:name => 'joe')
|
151
151
|
doc = @document.create(:name => 'joe')
|
152
152
|
doc.should have_error_on(:name, 'has already been taken')
|
153
153
|
end
|
154
154
|
|
155
|
-
should
|
155
|
+
it "should allow to update an object" do
|
156
156
|
doc = @document.new("name" => "joe")
|
157
157
|
doc.save.should be_true
|
158
158
|
|
159
159
|
@document \
|
160
|
-
.
|
160
|
+
.stub(:first) \
|
161
161
|
.with(:name => 'joe') \
|
162
|
-
.
|
162
|
+
.and_return(doc)
|
163
163
|
|
164
164
|
doc.name = "joe"
|
165
165
|
doc.valid?.should be_true
|
166
166
|
doc.should_not have_error_on(:name)
|
167
167
|
end
|
168
168
|
|
169
|
-
should
|
169
|
+
it "should fail if object name is not unique" do
|
170
170
|
doc = @document.new("name" => "joe")
|
171
171
|
doc.save.should be_true
|
172
172
|
|
173
173
|
@document \
|
174
|
-
.
|
174
|
+
.stub(:first) \
|
175
175
|
.with(:name => 'joe') \
|
176
|
-
.
|
176
|
+
.and_return(doc)
|
177
177
|
|
178
178
|
doc2 = @document.new("name" => "joe")
|
179
179
|
doc2.should have_error_on(:name)
|
180
180
|
end
|
181
181
|
|
182
|
-
should
|
182
|
+
it "should allow multiple blank entries if :allow_blank => true" do
|
183
183
|
document = Doc do
|
184
184
|
key :name
|
185
185
|
validates_uniqueness_of :name, :allow_blank => :true
|
@@ -189,15 +189,15 @@ class ValidationsTest < Test::Unit::TestCase
|
|
189
189
|
doc.save.should be_true
|
190
190
|
|
191
191
|
document \
|
192
|
-
.
|
192
|
+
.stub(:first) \
|
193
193
|
.with(:name => '') \
|
194
|
-
.
|
194
|
+
.and_return(doc)
|
195
195
|
|
196
196
|
doc2 = document.new("name" => "")
|
197
197
|
doc2.should_not have_error_on(:name)
|
198
198
|
end
|
199
199
|
|
200
|
-
should
|
200
|
+
it "should allow multiple nil entries if :allow_nil => true" do
|
201
201
|
document = Doc do
|
202
202
|
key :name
|
203
203
|
validates_uniqueness_of :name, :allow_nil => :true
|
@@ -210,7 +210,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
210
210
|
doc2.should_not have_error_on(:name)
|
211
211
|
end
|
212
212
|
|
213
|
-
should
|
213
|
+
it "should allow entries that differ only in case by default" do
|
214
214
|
document = Doc do
|
215
215
|
key :name
|
216
216
|
validates_uniqueness_of :name
|
@@ -224,14 +224,14 @@ class ValidationsTest < Test::Unit::TestCase
|
|
224
224
|
end
|
225
225
|
|
226
226
|
context "with :case_sensitive => false" do
|
227
|
-
|
227
|
+
before do
|
228
228
|
@document = Doc do
|
229
229
|
key :name
|
230
230
|
validates_uniqueness_of :name, :case_sensitive => false
|
231
231
|
end
|
232
232
|
end
|
233
233
|
|
234
|
-
should
|
234
|
+
it "should fail on entries that differ only in case" do
|
235
235
|
doc = @document.new("name" => "BLAMMO")
|
236
236
|
doc.save.should be_true
|
237
237
|
|
@@ -239,17 +239,17 @@ class ValidationsTest < Test::Unit::TestCase
|
|
239
239
|
doc2.should have_error_on(:name)
|
240
240
|
end
|
241
241
|
|
242
|
-
should
|
242
|
+
it "should not raise an error if value is nil" do
|
243
243
|
doc = @document.new("name" => nil)
|
244
244
|
lambda { doc.valid? }.should_not raise_error
|
245
245
|
end
|
246
246
|
|
247
|
-
should
|
247
|
+
it "should not raise an error if special Regexp characters used" do
|
248
248
|
doc = @document.new("name" => '?')
|
249
249
|
lambda { doc.valid? }.should_not raise_error
|
250
250
|
end
|
251
251
|
|
252
|
-
should
|
252
|
+
it "should check for uniqueness using entire string" do
|
253
253
|
doc = @document.new("name" => "John Doe")
|
254
254
|
doc.save.should be_true
|
255
255
|
|
@@ -259,7 +259,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
259
259
|
end
|
260
260
|
|
261
261
|
context "scoped by a single attribute" do
|
262
|
-
|
262
|
+
before do
|
263
263
|
@document = Doc do
|
264
264
|
key :name, String
|
265
265
|
key :scope, String
|
@@ -267,27 +267,27 @@ class ValidationsTest < Test::Unit::TestCase
|
|
267
267
|
end
|
268
268
|
end
|
269
269
|
|
270
|
-
should
|
270
|
+
it "should fail if the same name exists in the scope" do
|
271
271
|
doc = @document.new("name" => "joe", "scope" => "one")
|
272
272
|
doc.save.should be_true
|
273
273
|
|
274
274
|
@document \
|
275
|
-
.
|
275
|
+
.stub(:first) \
|
276
276
|
.with(:name => 'joe', :scope => "one") \
|
277
|
-
.
|
277
|
+
.and_return(doc)
|
278
278
|
|
279
279
|
doc2 = @document.new("name" => "joe", "scope" => "one")
|
280
280
|
doc2.should have_error_on(:name)
|
281
281
|
end
|
282
282
|
|
283
|
-
should
|
283
|
+
it "should pass if the same name exists in a different scope" do
|
284
284
|
doc = @document.new("name" => "joe", "scope" => "one")
|
285
285
|
doc.save.should be_true
|
286
286
|
|
287
287
|
@document \
|
288
|
-
.
|
288
|
+
.stub(:first) \
|
289
289
|
.with(:name => 'joe', :scope => 'two') \
|
290
|
-
.
|
290
|
+
.and_return(nil)
|
291
291
|
|
292
292
|
doc2 = @document.new("name" => "joe", "scope" => "two")
|
293
293
|
doc2.should_not have_error_on(:name)
|
@@ -295,7 +295,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
295
295
|
end
|
296
296
|
|
297
297
|
context "scoped by a multiple attributes" do
|
298
|
-
|
298
|
+
before do
|
299
299
|
@document = Doc do
|
300
300
|
key :name, String
|
301
301
|
key :first_scope, String
|
@@ -304,27 +304,27 @@ class ValidationsTest < Test::Unit::TestCase
|
|
304
304
|
end
|
305
305
|
end
|
306
306
|
|
307
|
-
should
|
307
|
+
it "should fail if the same name exists in the scope" do
|
308
308
|
doc = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
|
309
309
|
doc.save.should be_true
|
310
310
|
|
311
311
|
@document \
|
312
|
-
.
|
312
|
+
.stub(:first) \
|
313
313
|
.with(:name => 'joe', :first_scope => 'one', :second_scope => 'two') \
|
314
|
-
.
|
314
|
+
.and_return(doc)
|
315
315
|
|
316
316
|
doc2 = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
|
317
317
|
doc2.should have_error_on(:name)
|
318
318
|
end
|
319
319
|
|
320
|
-
should
|
320
|
+
it "should pass if the same name exists in a different scope" do
|
321
321
|
doc = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
|
322
322
|
doc.save.should be_true
|
323
323
|
|
324
324
|
@document \
|
325
|
-
.
|
325
|
+
.stub(:first) \
|
326
326
|
.with(:name => 'joe', :first_scope => 'one', :second_scope => 'one') \
|
327
|
-
.
|
327
|
+
.and_return(nil)
|
328
328
|
|
329
329
|
doc2 = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "one")
|
330
330
|
doc2.should_not have_error_on(:name)
|
@@ -333,7 +333,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
333
333
|
end
|
334
334
|
|
335
335
|
context "validating associated docs" do
|
336
|
-
|
336
|
+
before do
|
337
337
|
@child_class = EDoc do
|
338
338
|
key :name, :required => true
|
339
339
|
end
|
@@ -342,19 +342,19 @@ class ValidationsTest < Test::Unit::TestCase
|
|
342
342
|
@root_class.many :children, :class => @child_class
|
343
343
|
@root_class.validates_associated :children, :message => 'are invalid'
|
344
344
|
end
|
345
|
-
|
346
|
-
should
|
345
|
+
|
346
|
+
it "should pass if there are no associated docs" do
|
347
347
|
doc = @root_class.new
|
348
348
|
doc.save.should be_true
|
349
349
|
end
|
350
|
-
|
351
|
-
should
|
350
|
+
|
351
|
+
it "should pass if the associated doc is valid" do
|
352
352
|
doc = @root_class.new
|
353
353
|
doc.children.build(:name => 'Joe')
|
354
354
|
doc.save.should be_true
|
355
355
|
end
|
356
356
|
|
357
|
-
should
|
357
|
+
it "should fail if the associated doc is invalid" do
|
358
358
|
doc = @root_class.new
|
359
359
|
doc.children.build
|
360
360
|
doc.should have_error_on(:children, 'are invalid')
|
@@ -363,7 +363,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
363
363
|
end
|
364
364
|
|
365
365
|
context "validating associated docs with custom context" do
|
366
|
-
|
366
|
+
before do
|
367
367
|
@child_class = EDoc do
|
368
368
|
key :name
|
369
369
|
|
@@ -375,18 +375,18 @@ class ValidationsTest < Test::Unit::TestCase
|
|
375
375
|
@root_class.validates_associated :children, :context => :custom_context
|
376
376
|
end
|
377
377
|
|
378
|
-
should
|
378
|
+
it "should pass if there are no associated docs" do
|
379
379
|
doc = @root_class.new
|
380
380
|
doc.valid?(:custom_context).should be_true
|
381
381
|
end
|
382
382
|
|
383
|
-
should
|
383
|
+
it "should pass if the associated doc is valid" do
|
384
384
|
doc = @root_class.new
|
385
385
|
doc.children.build(:name => 'George')
|
386
386
|
doc.valid?(:custom_context).should be_true
|
387
387
|
end
|
388
388
|
|
389
|
-
should
|
389
|
+
it "should fail if the associated doc is invalid" do
|
390
390
|
doc = @root_class.new
|
391
391
|
doc.children.build(:name => 'Bob')
|
392
392
|
doc.valid?(:custom_context).should_not be_true
|
@@ -394,7 +394,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
394
394
|
|
395
395
|
end
|
396
396
|
# context "validates uniqueness of with :unique shortcut" do
|
397
|
-
# should
|
397
|
+
# it "should work" do
|
398
398
|
# @document = Doc do
|
399
399
|
# key :name, String, :unique => true
|
400
400
|
# end
|
@@ -403,9 +403,9 @@ class ValidationsTest < Test::Unit::TestCase
|
|
403
403
|
# doc.should_not have_error_on(:name)
|
404
404
|
#
|
405
405
|
# @document \
|
406
|
-
# .
|
406
|
+
# .stub(:first) \
|
407
407
|
# .with(:name => 'John') \
|
408
|
-
# .
|
408
|
+
# .and_return(doc)
|
409
409
|
#
|
410
410
|
# second_john = @document.create(:name => 'John')
|
411
411
|
# second_john.should have_error_on(:name, 'has already been taken')
|