minidoc 1.0.0.rc1 → 1.0.0.rc2
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/.codeclimate.yml +1 -1
- data/.rspec +2 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +2 -3
- data/README.md +1 -1
- data/Rakefile +3 -8
- data/lib/minidoc/finders.rb +6 -4
- data/lib/minidoc/version.rb +1 -1
- data/lib/minidoc.rb +1 -1
- data/{test → spec}/locale/en.yml +0 -0
- data/spec/minidoc/associations_spec.rb +88 -0
- data/spec/minidoc/connection_spec.rb +65 -0
- data/spec/minidoc/counters_spec.rb +42 -0
- data/spec/minidoc/finders_spec.rb +91 -0
- data/spec/minidoc/grid_spec.rb +38 -0
- data/spec/minidoc/read_only_spec.rb +28 -0
- data/spec/minidoc/timestamps_spec.rb +24 -0
- data/spec/minidoc/validations_spec.rb +64 -0
- data/spec/minidoc_spec.rb +379 -0
- data/{test/helper.rb → spec/spec_helper.rb} +10 -4
- metadata +25 -32
- data/test/activemodel_test.rb +0 -28
- data/test/belongs_to_test.rb +0 -82
- data/test/connection_test.rb +0 -20
- data/test/counters_test.rb +0 -48
- data/test/duplicate_key_test.rb +0 -21
- data/test/first_run_test.rb +0 -40
- data/test/grid_test.rb +0 -33
- data/test/persistence_test.rb +0 -198
- data/test/query_test.rb +0 -64
- data/test/read_only_test.rb +0 -34
- data/test/timestamps_test.rb +0 -21
- data/test/uniqueness_validator_test.rb +0 -68
- data/test/validations_test.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac23e96443960c47789feec77de1e521febb6813
|
4
|
+
data.tar.gz: 946ccd3f12984a8f148225336f12cf9320a15b57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef711ba9125436d4bc9d5c599169f35aaebb67aca99a87de0e76eada3badaa81cdc0ad1bd420310ac0ceacb94d00e7874777fbc00f2d412642888156b6908692
|
7
|
+
data.tar.gz: 8aa19f3f9798c80dbba905dfb50d8cb7adde092067325f952bf64e81b295dcf25c3024ca74379d5c52d4e831fed09c0ed840e382cb3d196b29555bd67a7972f7
|
data/.codeclimate.yml
CHANGED
data/.rspec
ADDED
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,20 @@
|
|
8
8
|
|
9
9
|
### Changes
|
10
10
|
|
11
|
+
## v1.0.0.rc2 (2016-10-26)
|
12
|
+
|
13
|
+
### New features
|
14
|
+
|
15
|
+
* Allow omitting selectors to finder methods. ([@maxjacobson][])
|
16
|
+
|
17
|
+
### Bug fixes
|
18
|
+
|
19
|
+
* Minidoc#reload will raise Minidoc::DocumentNotFoundError when the document no longer exists, rather than a nil error. ([@maxjacobson][])
|
20
|
+
|
21
|
+
### Changes
|
22
|
+
|
23
|
+
* Make Minidoc.wrap and Minidoc.from_db private. ([@maxjacobson][])
|
24
|
+
|
11
25
|
## v1.0.0.rc1 (2016-09-29)
|
12
26
|
|
13
27
|
### New features
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -144,7 +144,7 @@ When making a pull request, please update the [changelog](CHANGELOG.md).
|
|
144
144
|
|
145
145
|
* Update the changelog to mark the unreleased changes as part of the new release.
|
146
146
|
* Update the version.rb with the new version number
|
147
|
-
* Commit and push to master
|
147
|
+
* Commit and push to master (may need to make a Pull Request because master is protected)
|
148
148
|
* `rake release` which will
|
149
149
|
* tag the latest commit based on version.rb
|
150
150
|
* push to github
|
data/Rakefile
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
require "
|
2
|
+
require "rspec/core/rake_task"
|
3
3
|
|
4
|
-
|
5
|
-
t.libs.push "lib"
|
6
|
-
t.ruby_opts = %w[-W0]
|
7
|
-
t.test_files = FileList["test/*_test.rb"]
|
8
|
-
t.verbose = true
|
9
|
-
end
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
5
|
|
11
|
-
task :default => :
|
6
|
+
task :default => :spec
|
data/lib/minidoc/finders.rb
CHANGED
@@ -33,19 +33,21 @@ module Minidoc::Finders
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
def find_one(selector, options = {})
|
36
|
+
def find_one(selector = {}, options = {})
|
37
37
|
wrap(collection.find_one(selector, options))
|
38
38
|
end
|
39
39
|
|
40
|
-
def find_one!(
|
41
|
-
find_one(
|
40
|
+
def find_one!(selector = {}, options = {})
|
41
|
+
find_one(selector, options) or raise DocumentNotFoundError
|
42
42
|
end
|
43
43
|
|
44
|
-
def find_one_or_initialize(attributes, options = {})
|
44
|
+
def find_one_or_initialize(attributes = {}, options = {})
|
45
45
|
raise ArgumentError unless attributes.is_a?(Hash)
|
46
46
|
find_one(attributes, options) || new(attributes)
|
47
47
|
end
|
48
48
|
|
49
|
+
private
|
50
|
+
|
49
51
|
def from_db(attrs)
|
50
52
|
doc = new(attrs)
|
51
53
|
doc.instance_variable_set("@new_record", false)
|
data/lib/minidoc/version.rb
CHANGED
data/lib/minidoc.rb
CHANGED
data/{test → spec}/locale/en.yml
RENAMED
File without changes
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Minidoc::Associations do
|
4
|
+
class Cat < Minidoc
|
5
|
+
include Minidoc::Associations
|
6
|
+
|
7
|
+
belongs_to :owner, class_name: "User"
|
8
|
+
end
|
9
|
+
|
10
|
+
class Doggie < Minidoc
|
11
|
+
include Minidoc::Associations
|
12
|
+
|
13
|
+
belongs_to :user
|
14
|
+
end
|
15
|
+
|
16
|
+
module Animal
|
17
|
+
class Armadillo < Minidoc
|
18
|
+
include Minidoc::Associations
|
19
|
+
|
20
|
+
belongs_to :predator
|
21
|
+
end
|
22
|
+
|
23
|
+
class Predator < Minidoc
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "dynamically defined association methods" do
|
28
|
+
it "can load associated documents" do
|
29
|
+
expect(Cat.new.owner).to be_nil
|
30
|
+
user = User.create
|
31
|
+
cat = Cat.new(owner_id: user.id)
|
32
|
+
expect(cat.owner.id).to eq user.id
|
33
|
+
cat.save
|
34
|
+
expect(cat.owner.id).to eq user.id
|
35
|
+
end
|
36
|
+
|
37
|
+
it "caches the association cache rather than go to the database each time" do
|
38
|
+
user = User.create(name: "Bryan")
|
39
|
+
cat = Cat.create(owner_id: user.id)
|
40
|
+
expect(cat.owner.name).to eq "Bryan"
|
41
|
+
user.set(name: "Noah")
|
42
|
+
expect(cat.owner.name).to eq "Bryan"
|
43
|
+
expect(cat.reload.owner.name).to eq "Noah"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "expires the association cache when a new associated document is provided" do
|
47
|
+
user = User.create(name: "Bryan")
|
48
|
+
cat = Cat.create(owner_id: user.id)
|
49
|
+
expect(cat.owner.name).to eq "Bryan"
|
50
|
+
user.set(name: "Noah")
|
51
|
+
expect(cat.owner.name).to eq "Bryan"
|
52
|
+
cat.owner = user
|
53
|
+
expect(cat.owner.name).to eq "Noah"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "expires the association cache when the related foreign-key id field is updated" do
|
57
|
+
user = User.create(name: "Bryan")
|
58
|
+
cat = Cat.create(owner_id: user.id)
|
59
|
+
expect(cat.owner.name).to eq "Bryan"
|
60
|
+
user.set(name: "Noah")
|
61
|
+
expect(cat.owner.name).to eq "Bryan"
|
62
|
+
cat.owner_id = user.id
|
63
|
+
expect(cat.owner.name).to eq "Noah"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when the classes are not namespaced" do
|
68
|
+
it "infers the class name of the association" do
|
69
|
+
expect(Doggie.new.user).to be_nil
|
70
|
+
user = User.create
|
71
|
+
sam = Doggie.new(user_id: user.id)
|
72
|
+
expect(sam.user.id).to eq user.id
|
73
|
+
sam.save
|
74
|
+
expect(sam.user.id).to eq user.id
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when the classes are namespaced" do
|
79
|
+
it "infers the class name of the association" do
|
80
|
+
expect(Animal::Armadillo.new.predator).to be_nil
|
81
|
+
predator = Animal::Predator.create
|
82
|
+
arnie = Animal::Armadillo.new(predator_id: predator.id)
|
83
|
+
expect(arnie.predator.id).to eq predator.id
|
84
|
+
arnie.save
|
85
|
+
expect(arnie.predator.id).to eq predator.id
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe "connection" do
|
5
|
+
class Company < Minidoc
|
6
|
+
self.collection_name = "accounts"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ".collection_name" do
|
10
|
+
it "is inferred based on the class name" do
|
11
|
+
expect(User.collection_name).to eq "users"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can be overridden" do
|
15
|
+
expect(Company.collection_name).to eq "accounts"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".collection" do
|
20
|
+
it "exposes the underlying Mongo object" do
|
21
|
+
expect(User.collection).to be_a Mongo::Collection
|
22
|
+
end
|
23
|
+
|
24
|
+
it "passes through the collection_name to the underlying Mongo::Collection" do
|
25
|
+
expect(User.collection.name).to eq "users"
|
26
|
+
expect(Company.collection.name).to eq "accounts"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe ".database" do
|
31
|
+
it "exposes the underlying Mongo object" do
|
32
|
+
expect(User.database).to be_a Mongo::DB
|
33
|
+
end
|
34
|
+
|
35
|
+
it "passes through the database name to the underlying Mongo::DB" do
|
36
|
+
expect(User.database.name).to eq "minidoc_test"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "first run experience" do
|
41
|
+
it "fails helpfully if you haven't configured the necessary values" do
|
42
|
+
with_alternative_configuration do
|
43
|
+
Minidoc.connection = nil
|
44
|
+
Minidoc.database_name = nil
|
45
|
+
expect { User.create(name: "Kären") }.to raise_error(Minidoc::MissingConfiguration, "Make sure to set Minidoc.connection")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "fails helpfully if you've only neglected the database_name" do
|
50
|
+
with_alternative_configuration do
|
51
|
+
Minidoc.database_name = nil
|
52
|
+
expect { User.create(name: "Kären") }.to raise_error(Minidoc::MissingConfiguration, "Make sure to set Minidoc.database_name")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def with_alternative_configuration
|
58
|
+
original_connection = Minidoc.connection
|
59
|
+
original_database_name = Minidoc.database_name
|
60
|
+
yield
|
61
|
+
ensure
|
62
|
+
Minidoc.connection = original_connection
|
63
|
+
Minidoc.database_name = original_database_name
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Minidoc::Counters do
|
4
|
+
class SimpleCounter < Minidoc
|
5
|
+
include Minidoc::Counters
|
6
|
+
|
7
|
+
counter :counter
|
8
|
+
end
|
9
|
+
|
10
|
+
class AdvancedCounter < Minidoc
|
11
|
+
include Minidoc::Counters
|
12
|
+
|
13
|
+
counter :counter, start: 2, step_size: 3
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#increment_counter" do
|
17
|
+
it "increments the field" do
|
18
|
+
x = SimpleCounter.create!
|
19
|
+
expect(x.counter).to eq 0
|
20
|
+
expect(x.increment_counter).to eq 1
|
21
|
+
expect(x.increment_counter).to eq 2
|
22
|
+
expect(x.increment_counter).to eq 3
|
23
|
+
expect(x.reload.counter).to eq 3
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can be customized with some options" do
|
27
|
+
x = AdvancedCounter.create!
|
28
|
+
expect(x.counter).to eq 2
|
29
|
+
expect(x.increment_counter).to eq 5
|
30
|
+
expect(x.increment_counter).to eq 8
|
31
|
+
expect(x.increment_counter).to eq 11
|
32
|
+
expect(x.reload.counter).to eq 11
|
33
|
+
end
|
34
|
+
|
35
|
+
it "is thread safe" do
|
36
|
+
x = SimpleCounter.create!
|
37
|
+
counters = []
|
38
|
+
[Thread.new { 5.times { (counters << x.increment_counter) } }, Thread.new { 5.times { (counters << x.increment_counter) } }, Thread.new { 5.times { (counters << x.increment_counter) } }].map(&:join)
|
39
|
+
expect(counters.uniq.length).to eq 15
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Minidoc::Finders do
|
4
|
+
describe ".all" do
|
5
|
+
it "returns all of the documents in the collection" do
|
6
|
+
(User.collection << { name: "Joe" })
|
7
|
+
(User.collection << { name: "Bryan" })
|
8
|
+
users = User.all
|
9
|
+
expect(["Bryan", "Joe"]).to match_array(users.map(&:name))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".count" do
|
14
|
+
it "counts the documents in the collection" do
|
15
|
+
(User.collection << { name: "Joe" })
|
16
|
+
(User.collection << { name: "Bryan" })
|
17
|
+
expect(User.count).to eq 2
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can be scoped by a query" do
|
21
|
+
(User.collection << { name: "Joe" })
|
22
|
+
(User.collection << { name: "Bryan" })
|
23
|
+
expect(User.count(name: "Bryan")).to eq 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe ".exists?" do
|
28
|
+
it "tells you if any documents exist that match a query" do
|
29
|
+
(User.collection << { name: "Joe" })
|
30
|
+
expect(User.exists?(name: "Joe")).to be(true)
|
31
|
+
expect(User.exists?(name: "Bryan")).to be(false)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".first" do
|
36
|
+
it "returns a document from the collection" do
|
37
|
+
expect(User.first).to be_nil
|
38
|
+
user = User.create(name: "Bryan")
|
39
|
+
expect(User.first.name).to eq "Bryan"
|
40
|
+
expect(User.first).to eq user
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".find" do
|
45
|
+
it "querys the collection using the mongodb query language" do
|
46
|
+
user = User.create(name: "Bryan")
|
47
|
+
expect(User.find({}).to_a).to eq [user]
|
48
|
+
expect(User.find(name: "Noah").to_a).to eq []
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe ".find_one" do
|
53
|
+
it "returns the first document that matches a query" do
|
54
|
+
user = User.create(name: "Bryan")
|
55
|
+
expect(User.find_one({})).to eq user
|
56
|
+
expect(User.find_one).to eq user
|
57
|
+
expect(User.find_one(name: "Noah")).to eq nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe ".find_one!" do
|
62
|
+
it "returns the first document that matches a query or raises an error" do
|
63
|
+
expect { User.find_one! }.to raise_error(Minidoc::DocumentNotFoundError)
|
64
|
+
user = User.create(name: "Bryan")
|
65
|
+
expect(User.find_one!(name: "Bryan")).to eq user
|
66
|
+
expect(User.find_one!).to eq user
|
67
|
+
expect { User.find_one!(name: "Noah") }.to raise_error(Minidoc::DocumentNotFoundError)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe ".find_one_or_initialize" do
|
72
|
+
it "returns the first document that matches a query or makes a non-persisted document from that query" do
|
73
|
+
user = User.create(name: "Bryan", age: 1)
|
74
|
+
expect((user == User.find_one_or_initialize(name: "Bryan"))).to be_truthy
|
75
|
+
expect(User.find_one_or_initialize(name: "Noah").is_a?(User)).to eq true
|
76
|
+
expect(User.find_one_or_initialize(name: "Noah").new_record?).to eq true
|
77
|
+
end
|
78
|
+
|
79
|
+
it "doesn't require attributes" do
|
80
|
+
expect(User.find_one_or_initialize).to be_a User
|
81
|
+
user = User.create(name: "Bryan", age: 1)
|
82
|
+
expect(user).to eq User.find_one_or_initialize
|
83
|
+
end
|
84
|
+
|
85
|
+
it "allows query options" do
|
86
|
+
user = User.create(name: "Noah", age: 1)
|
87
|
+
expect((user == User.find_one_or_initialize({ age: 1 }, sort: { name: -1 }))).to be_truthy
|
88
|
+
expect { User.find_one_or_initialize("foo") }.to raise_error(ArgumentError)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Minidoc::Grid do
|
4
|
+
let(:grid) { Minidoc::Grid.new(Minidoc.database) }
|
5
|
+
|
6
|
+
describe "#put and #get" do
|
7
|
+
it "can store raw string data" do
|
8
|
+
doc_id = grid.put "estamos en espana"
|
9
|
+
expect(doc_id).to be_a BSON::ObjectId
|
10
|
+
|
11
|
+
document = grid.get doc_id.to_s
|
12
|
+
|
13
|
+
expect(document).to be_a Mongo::GridIO
|
14
|
+
expect(document.read).to eq "estamos en espana"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#get_json" do
|
19
|
+
it "parses the JSON into structured ruby objects" do
|
20
|
+
hash = { "foo" => { "bar" => 1 } }
|
21
|
+
doc_id = grid.put(hash.to_json)
|
22
|
+
|
23
|
+
value = grid.get_json(doc_id.to_s)
|
24
|
+
|
25
|
+
expect(value).to eq hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#delete" do
|
30
|
+
it "removes the 'file' from the database" do
|
31
|
+
doc_id = grid.put "estamos en espana"
|
32
|
+
|
33
|
+
grid.delete doc_id.to_s
|
34
|
+
|
35
|
+
expect { grid.get doc_id }.to raise_error(Mongo::GridFileNotFound)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Minidoc::ReadOnly do
|
4
|
+
class ReadOnlyUser < Minidoc::ReadOnly
|
5
|
+
self.collection_name = "users"
|
6
|
+
attribute :name, String
|
7
|
+
end
|
8
|
+
|
9
|
+
it "is read only, meaning it can't change over time" do
|
10
|
+
expect { ReadOnlyUser.create(name: "Bryan") }.to raise_error(NoMethodError)
|
11
|
+
|
12
|
+
rw_user = User.create(name: "Bryan")
|
13
|
+
user = ReadOnlyUser.first
|
14
|
+
expect(user.name).to eq "Bryan"
|
15
|
+
expect(rw_user.id).to eq user.id
|
16
|
+
expect(user).to eq user.as_value
|
17
|
+
|
18
|
+
expect { user.name = "Noah" }.to raise_error(NoMethodError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can become a value object" do
|
22
|
+
user = User.new(name: "Bryan")
|
23
|
+
user.name = "Noah"
|
24
|
+
user = user.as_value
|
25
|
+
|
26
|
+
expect { user.name = "Noah" }.to raise_error(NoMethodError)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Minidoc::Timestamps do
|
4
|
+
class TimestampsUser < Minidoc
|
5
|
+
include Minidoc::Timestamps
|
6
|
+
|
7
|
+
timestamps!
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".timestamps!" do
|
11
|
+
it "automatically sets created_at and updated_at" do
|
12
|
+
user = TimestampsUser.create!
|
13
|
+
expect(user.created_at).to_not be_nil
|
14
|
+
expect(user.created_at).to eq user.updated_at
|
15
|
+
end
|
16
|
+
|
17
|
+
it "updates the updated_at when the document changes" do
|
18
|
+
user = TimestampsUser.create
|
19
|
+
sleep 0.001
|
20
|
+
user.save
|
21
|
+
expect(user.created_at).to_not eq user.updated_at
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Minidoc::Validations do
|
4
|
+
describe Minidoc::Validations::UniquenessValidator do
|
5
|
+
class UniquenessUser < User
|
6
|
+
validates :name, uniqueness: true
|
7
|
+
end
|
8
|
+
|
9
|
+
class InsensitiveUser < User
|
10
|
+
attribute :insensitive, String
|
11
|
+
validates :insensitive, uniqueness: { case_sensitive: false }
|
12
|
+
end
|
13
|
+
|
14
|
+
class ScopedUser < User
|
15
|
+
attribute :country_id, Integer
|
16
|
+
attribute :tax_id_number, Integer
|
17
|
+
validates :tax_id_number, uniqueness: { scope: :country_id }
|
18
|
+
end
|
19
|
+
|
20
|
+
it "is invalid with existing value" do
|
21
|
+
UniquenessUser.create!(name: "same name")
|
22
|
+
user = UniquenessUser.new(name: "same name")
|
23
|
+
expect(user).to_not be_valid
|
24
|
+
expect(user.errors[:name]).to eq ["has already been taken"]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "is case insensitive by default" do
|
28
|
+
UniquenessUser.create!(name: "different case")
|
29
|
+
user = UniquenessUser.new(name: "DIFFERENT CASE")
|
30
|
+
expect(user).to be_valid
|
31
|
+
end
|
32
|
+
|
33
|
+
it "persists a document that passes validations" do
|
34
|
+
user = UniquenessUser.create!(name: "lonely")
|
35
|
+
expect(user).to be_valid
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can be made case insensitive" do
|
39
|
+
InsensitiveUser.create!(insensitive: "equivalent")
|
40
|
+
user = InsensitiveUser.new(insensitive: "EquivALENT")
|
41
|
+
expect(user).to_not be_valid
|
42
|
+
expect(user.errors["insensitive"]).to eq ["has already been taken"]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "does not allow the same value within a scope" do
|
46
|
+
ScopedUser.create!(country_id: 1, tax_id_number: 1)
|
47
|
+
user = ScopedUser.new(country_id: 1, tax_id_number: 1)
|
48
|
+
expect(user).to_not be_valid
|
49
|
+
expect(user.errors[:tax_id_number]).to eq ["has already been taken"]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "allows a different value within the same scope" do
|
53
|
+
ScopedUser.create!(country_id: 1, tax_id_number: 1)
|
54
|
+
user = ScopedUser.new(country_id: 1, tax_id_number: 2)
|
55
|
+
expect(user).to be_valid
|
56
|
+
end
|
57
|
+
|
58
|
+
it "does allow the same value in a different scope" do
|
59
|
+
ScopedUser.create!(country_id: 1, tax_id_number: 1)
|
60
|
+
user = ScopedUser.new(country_id: 2, tax_id_number: 1)
|
61
|
+
expect(user).to be_valid
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|