mongoid-rspec 1.5.3 → 2.0.0
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 +7 -0
- data/.gitignore +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -2
- data/README.md +227 -152
- data/lib/matchers/accept_nested_attributes.rb +67 -0
- data/lib/matchers/allow_mass_assignment.rb +1 -0
- data/lib/matchers/associations.rb +127 -22
- data/lib/matchers/document.rb +31 -2
- data/lib/matchers/indexes.rb +48 -15
- data/lib/matchers/validations/acceptance_of.rb +2 -2
- data/lib/matchers/validations/associated.rb +5 -5
- data/lib/matchers/validations/confirmation_of.rb +2 -2
- data/lib/matchers/validations/custom_validation_of.rb +2 -19
- data/lib/matchers/validations/exclusion_of.rb +8 -1
- data/lib/matchers/validations/format_of.rb +21 -21
- data/lib/matchers/validations/inclusion_of.rb +13 -13
- data/lib/matchers/validations/length_of.rb +66 -19
- data/lib/matchers/validations/numericality_of.rb +10 -10
- data/lib/matchers/validations/presence_of.rb +2 -2
- data/lib/matchers/validations/uniqueness_of.rb +13 -30
- data/lib/matchers/validations/with_message.rb +27 -0
- data/lib/matchers/validations.rb +18 -3
- data/lib/mongoid-rspec/version.rb +1 -1
- data/lib/mongoid-rspec.rb +5 -1
- data/mongoid-rspec.gemspec +5 -5
- data/spec/models/article.rb +18 -12
- data/spec/models/comment.rb +2 -2
- data/spec/models/movie_article.rb +6 -5
- data/spec/models/permalink.rb +1 -1
- data/spec/models/person.rb +0 -3
- data/spec/models/profile.rb +9 -7
- data/spec/models/record.rb +1 -1
- data/spec/models/site.rb +2 -3
- data/spec/models/user.rb +14 -14
- data/spec/unit/accept_nested_attributes_spec.rb +12 -0
- data/spec/unit/associations_spec.rb +6 -6
- data/spec/unit/document_spec.rb +6 -6
- data/spec/unit/indexes_spec.rb +3 -2
- data/spec/unit/validations_spec.rb +7 -0
- data/spec/validators/ssn_validator.rb +3 -1
- metadata +43 -32
- data/.rvmrc +0 -1
- data/spec/unit/allow_mass_assignment_spec.rb +0 -14
|
@@ -2,6 +2,8 @@ module Mongoid
|
|
|
2
2
|
module Matchers
|
|
3
3
|
module Validations
|
|
4
4
|
class ValidateLengthOfMatcher < HaveValidationMatcher
|
|
5
|
+
include WithMessage
|
|
6
|
+
|
|
5
7
|
def initialize(name)
|
|
6
8
|
super(name, :length)
|
|
7
9
|
end
|
|
@@ -10,11 +12,13 @@ module Mongoid
|
|
|
10
12
|
@maximum = value
|
|
11
13
|
self
|
|
12
14
|
end
|
|
15
|
+
alias :less_than :with_maximum
|
|
13
16
|
|
|
14
17
|
def with_minimum(value)
|
|
15
18
|
@minimum = value
|
|
16
19
|
self
|
|
17
20
|
end
|
|
21
|
+
alias :greater_than :with_minimum
|
|
18
22
|
|
|
19
23
|
def within(value)
|
|
20
24
|
@within = value
|
|
@@ -28,6 +32,11 @@ module Mongoid
|
|
|
28
32
|
end
|
|
29
33
|
alias :is :as_exactly
|
|
30
34
|
|
|
35
|
+
def with_message(message)
|
|
36
|
+
@expected_message = message
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
31
40
|
def matches?(actual)
|
|
32
41
|
return false unless @result = super(actual)
|
|
33
42
|
|
|
@@ -35,61 +44,99 @@ module Mongoid
|
|
|
35
44
|
check_minimum if @minimum
|
|
36
45
|
check_range if @within
|
|
37
46
|
check_exact if @is
|
|
47
|
+
check_expected_message if @expected_message
|
|
38
48
|
|
|
39
49
|
@result
|
|
40
50
|
end
|
|
41
51
|
|
|
42
52
|
def description
|
|
43
53
|
options_desc = []
|
|
44
|
-
options_desc << "
|
|
45
|
-
options_desc << "
|
|
46
|
-
options_desc << "
|
|
47
|
-
options_desc << "
|
|
48
|
-
|
|
54
|
+
options_desc << "with minimum of #{@minimum}" if @minimum
|
|
55
|
+
options_desc << "with maximum of #{@maximum}" if @maximum
|
|
56
|
+
options_desc << "within the range of #{@within}" if @within
|
|
57
|
+
options_desc << "as exactly #{@is}" if @is
|
|
58
|
+
options_desc << "with message '#{@expected_message}'" if @expected_message
|
|
59
|
+
super << " #{options_desc.to_sentence}"
|
|
49
60
|
end
|
|
50
61
|
|
|
51
62
|
private
|
|
52
63
|
|
|
53
64
|
def check_maximum
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
if actual_max.nil?
|
|
66
|
+
@negative_result_message << " with no maximum"
|
|
67
|
+
@result = false
|
|
68
|
+
elsif actual_max == @maximum
|
|
56
69
|
@positive_result_message << " with maximum of #{@maximum}"
|
|
57
70
|
else
|
|
58
|
-
@negative_result_message << " with maximum of #{
|
|
71
|
+
@negative_result_message << " with maximum of #{actual_max}"
|
|
59
72
|
@result = false
|
|
60
73
|
end
|
|
61
74
|
end
|
|
62
75
|
|
|
63
76
|
def check_minimum
|
|
64
|
-
|
|
65
|
-
|
|
77
|
+
if actual_min.nil?
|
|
78
|
+
@negative_result_message << " with no minimum"
|
|
79
|
+
@result = false
|
|
80
|
+
elsif actual_min == @minimum
|
|
66
81
|
@positive_result_message << " with minimum of #{@minimum}"
|
|
67
82
|
else
|
|
68
|
-
@negative_result_message << " with minimum of #{
|
|
83
|
+
@negative_result_message << " with minimum of #{actual_min}"
|
|
69
84
|
@result = false
|
|
70
85
|
end
|
|
71
86
|
end
|
|
72
87
|
|
|
73
88
|
def check_range
|
|
74
89
|
min, max = [@within.min, @within.max]
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@
|
|
90
|
+
if !actual_min.nil? and actual_max.nil?
|
|
91
|
+
@negative_result_message << " with no minimum but with maximum of #{actual_max}"
|
|
92
|
+
@result = false
|
|
93
|
+
elsif actual_min.nil? and !actual_max.nil?
|
|
94
|
+
@negative_result_message << " with minimum_of #{actual_min} but no maximum"
|
|
95
|
+
@result = false
|
|
96
|
+
elsif actual_min.nil? and actual_max.nil?
|
|
97
|
+
@negative_result_message << " with no minimum and maximum"
|
|
98
|
+
@result = false
|
|
99
|
+
elsif actual_min == min && actual_max == max
|
|
100
|
+
@positive_result_message << " within the range of #{@within.inspect}"
|
|
78
101
|
else
|
|
79
|
-
@negative_result_message << "
|
|
102
|
+
@negative_result_message << " within the range of #{(actual_min..actual_max).inspect}"
|
|
80
103
|
@result = false
|
|
81
104
|
end
|
|
82
105
|
end
|
|
83
106
|
|
|
84
107
|
def check_exact
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@positive_result_message << " is exactly #{@is}"
|
|
108
|
+
if actual_is == @is
|
|
109
|
+
@positive_result_message << " as exactly #{@is}"
|
|
88
110
|
else
|
|
89
|
-
@negative_result_message << "
|
|
111
|
+
@negative_result_message << " as exactly #{actual_is}"
|
|
90
112
|
@result = false
|
|
91
113
|
end
|
|
92
114
|
end
|
|
115
|
+
|
|
116
|
+
def check_expected_message
|
|
117
|
+
actual_message = @validator.options[:message]
|
|
118
|
+
if actual_message.nil?
|
|
119
|
+
@negative_result_message << " with no custom message"
|
|
120
|
+
@result = false
|
|
121
|
+
elsif actual_message == @expected_message
|
|
122
|
+
@positive_result_message << " with custom message '#{@expected_message}'"
|
|
123
|
+
else
|
|
124
|
+
@negative_result_message << " got message '#{actual_message}'"
|
|
125
|
+
@result = false
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def actual_is
|
|
130
|
+
actual_is = @validator.options[:is]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def actual_min
|
|
134
|
+
@validator.options[:minimum] || ((@validator.options[:in] || @validator.options[:within]).try(&:min))
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def actual_max
|
|
138
|
+
@validator.options[:maximum] || ((@validator.options[:in] || @validator.options[:within]).try(&:max))
|
|
139
|
+
end
|
|
93
140
|
end
|
|
94
141
|
|
|
95
142
|
def validate_length_of(field)
|
|
@@ -2,14 +2,14 @@ module Mongoid
|
|
|
2
2
|
module Matchers
|
|
3
3
|
module Validations
|
|
4
4
|
class ValidateNumericalityOfMatcher < HaveValidationMatcher
|
|
5
|
-
@@allowed_options = [:equal_to, :greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to,
|
|
5
|
+
@@allowed_options = [:equal_to, :greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to,
|
|
6
6
|
:even, :odd, :only_integer, :allow_nil, :nil]
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
def initialize(field)
|
|
9
9
|
super(field, :numericality)
|
|
10
10
|
@options = {}
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
def to_allow(options)
|
|
14
14
|
options[:equal_to] = options if options.is_a?(Numeric)
|
|
15
15
|
options[:allow_nil] = options.delete(:nil) if options.has_key?(:nil)
|
|
@@ -21,7 +21,7 @@ module Mongoid
|
|
|
21
21
|
|
|
22
22
|
def matches?(actual)
|
|
23
23
|
return false unless result = super(actual)
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
@@allowed_options.each do |comparator|
|
|
26
26
|
if @options.has_key?(comparator) and !([:even, :odd, :only_integer].include?(comparator) and !@validator.options.include?(comparator))
|
|
27
27
|
result &= (@validator.options[comparator] == @options[comparator])
|
|
@@ -35,12 +35,12 @@ module Mongoid
|
|
|
35
35
|
def description
|
|
36
36
|
super << options_message(@options)
|
|
37
37
|
end
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
protected
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
def options_message(options)
|
|
42
42
|
type_msg = []
|
|
43
|
-
comp_msg = []
|
|
43
|
+
comp_msg = []
|
|
44
44
|
options.each_pair do |key, value|
|
|
45
45
|
case key
|
|
46
46
|
when :allow_nil
|
|
@@ -52,10 +52,10 @@ module Mongoid
|
|
|
52
52
|
comp_msg << "#{key.to_s.gsub("_", " ")} #{value.inspect}"
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
|
-
allow_nil = (options[:allow_nil] ? "nil" : "non-nil") if options.has_key?(:allow_nil)
|
|
55
|
+
allow_nil = (options[:allow_nil] ? "nil" : "non-nil") if options.has_key?(:allow_nil)
|
|
56
56
|
["", "allowing", allow_nil, type_msg.any? ? type_msg.to_sentence : nil, "values", comp_msg.any? ? comp_msg.to_sentence : nil].compact.join(" ")
|
|
57
|
-
end
|
|
58
|
-
|
|
57
|
+
end
|
|
58
|
+
|
|
59
59
|
def method_missing(m, *args, &block)
|
|
60
60
|
if @@allowed_options.include?(m.to_sym)
|
|
61
61
|
raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" if args.length > 1
|
|
@@ -1,40 +1,36 @@
|
|
|
1
1
|
module Mongoid
|
|
2
2
|
module Matchers
|
|
3
|
-
module Validations
|
|
3
|
+
module Validations
|
|
4
4
|
class ValidateUniquenessOfMatcher < HaveValidationMatcher
|
|
5
|
+
include WithMessage
|
|
5
6
|
def initialize(field)
|
|
6
7
|
super(field, :uniqueness)
|
|
7
8
|
end
|
|
8
|
-
|
|
9
|
+
|
|
9
10
|
def scoped_to(*scope)
|
|
10
11
|
@scope = [scope].flatten.map(&:to_sym)
|
|
11
12
|
self
|
|
12
|
-
end
|
|
13
|
+
end
|
|
13
14
|
alias_method :scoped_on, :scoped_to
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
def case_insensitive
|
|
16
17
|
@case_insensitive = true
|
|
17
18
|
self
|
|
18
19
|
end
|
|
19
|
-
|
|
20
|
+
|
|
20
21
|
def allow_blank?(allow_blank)
|
|
21
22
|
@allow_blank = allow_blank
|
|
22
23
|
self
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
def with_message(message)
|
|
26
|
-
@expected_message = message
|
|
27
|
-
self
|
|
28
|
-
end
|
|
29
|
-
|
|
30
26
|
def matches?(actual)
|
|
31
27
|
return false unless @result = super(actual)
|
|
32
|
-
|
|
28
|
+
|
|
33
29
|
check_scope if @scope
|
|
34
30
|
check_allow_blank if @allow_blank
|
|
35
31
|
check_case_sensitivity if @case_insensitive
|
|
36
32
|
check_expected_message if @expected_message
|
|
37
|
-
|
|
33
|
+
|
|
38
34
|
@result
|
|
39
35
|
end
|
|
40
36
|
|
|
@@ -46,7 +42,7 @@ module Mongoid
|
|
|
46
42
|
options_desc << " with message '#{@expected_message}'" if @expected_message
|
|
47
43
|
super << options_desc.to_sentence
|
|
48
44
|
end
|
|
49
|
-
|
|
45
|
+
|
|
50
46
|
private
|
|
51
47
|
|
|
52
48
|
def check_allow_blank
|
|
@@ -67,7 +63,7 @@ module Mongoid
|
|
|
67
63
|
@result = false
|
|
68
64
|
end
|
|
69
65
|
end
|
|
70
|
-
|
|
66
|
+
|
|
71
67
|
def check_case_sensitivity
|
|
72
68
|
if @validator.options[:case_sensitive] == false
|
|
73
69
|
@positive_result_message << " with case insensitive values"
|
|
@@ -76,24 +72,11 @@ module Mongoid
|
|
|
76
72
|
@result = false
|
|
77
73
|
end
|
|
78
74
|
end
|
|
79
|
-
|
|
80
|
-
def check_expected_message
|
|
81
|
-
actual_message = @validator.options[:message]
|
|
82
|
-
if actual_message.nil?
|
|
83
|
-
@negative_result_message << " with no custom message"
|
|
84
|
-
@result = false
|
|
85
|
-
elsif actual_message == @expected_message
|
|
86
|
-
@positive_result_message << " with custom message '#{@expected_message}'"
|
|
87
|
-
else
|
|
88
|
-
@negative_result_message << " got message '#{actual_message}'"
|
|
89
|
-
@result = false
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
75
|
end
|
|
93
|
-
|
|
76
|
+
|
|
94
77
|
def validate_uniqueness_of(field)
|
|
95
78
|
ValidateUniquenessOfMatcher.new(field)
|
|
96
|
-
end
|
|
79
|
+
end
|
|
97
80
|
end
|
|
98
81
|
end
|
|
99
|
-
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Mongoid
|
|
2
|
+
module Matchers
|
|
3
|
+
module Validations
|
|
4
|
+
module WithMessage
|
|
5
|
+
def with_message(message)
|
|
6
|
+
@expected_message = message
|
|
7
|
+
self
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def check_expected_message
|
|
13
|
+
actual_message = @validator.options[:message]
|
|
14
|
+
if actual_message.nil?
|
|
15
|
+
@negative_result_message << " with no custom message"
|
|
16
|
+
@result = false
|
|
17
|
+
elsif actual_message == @expected_message
|
|
18
|
+
@positive_result_message << " with custom message '#{@expected_message}'"
|
|
19
|
+
else
|
|
20
|
+
@negative_result_message << " got message '#{actual_message}'"
|
|
21
|
+
@result = false
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/matchers/validations.rb
CHANGED
|
@@ -13,7 +13,9 @@ module Mongoid
|
|
|
13
13
|
def matches?(actual)
|
|
14
14
|
@klass = actual.is_a?(Class) ? actual : actual.class
|
|
15
15
|
|
|
16
|
-
@validator = @klass.validators_on(@field).detect{|v|
|
|
16
|
+
@validator = @klass.validators_on(@field).detect{ |v|
|
|
17
|
+
v.kind.to_s == @type and (!v.options[:on] or on_options_matches?(v))
|
|
18
|
+
}
|
|
17
19
|
|
|
18
20
|
if @validator
|
|
19
21
|
@negative_result_message = "#{@type.inspect} validator on #{@field.inspect}"
|
|
@@ -35,8 +37,11 @@ module Mongoid
|
|
|
35
37
|
"Expected #{@klass.inspect} to not #{description}; instead got #{@positive_result_message}"
|
|
36
38
|
end
|
|
37
39
|
|
|
40
|
+
alias :failure_message :failure_message_for_should
|
|
41
|
+
alias :failure_message_when_negated :failure_message_for_should_not
|
|
42
|
+
|
|
38
43
|
def description
|
|
39
|
-
desc = "
|
|
44
|
+
desc = "have #{@type.inspect} validator on #{@field.inspect}"
|
|
40
45
|
desc << " on #{@options[:on]}" if @options[:on]
|
|
41
46
|
desc
|
|
42
47
|
end
|
|
@@ -52,7 +57,7 @@ module Mongoid
|
|
|
52
57
|
if validator_on_methods.any?
|
|
53
58
|
message = " on methods: #{validator_on_methods}"
|
|
54
59
|
|
|
55
|
-
if (@
|
|
60
|
+
if on_options_covered_by?( @validator )
|
|
56
61
|
@positive_result_message << message
|
|
57
62
|
else
|
|
58
63
|
@negative_result_message << message
|
|
@@ -60,6 +65,16 @@ module Mongoid
|
|
|
60
65
|
end
|
|
61
66
|
end
|
|
62
67
|
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def on_options_matches?(validator)
|
|
72
|
+
@options[:on] and validator.options[:on] and on_options_covered_by?(validator)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def on_options_covered_by?(validator)
|
|
76
|
+
([@options[:on]].flatten - [validator.options[:on]].flatten).empty?
|
|
77
|
+
end
|
|
63
78
|
end
|
|
64
79
|
end
|
|
65
80
|
end
|
data/lib/mongoid-rspec.rb
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
2
2
|
|
|
3
3
|
require 'mongoid'
|
|
4
|
-
require 'rspec'
|
|
4
|
+
require 'rspec/core'
|
|
5
|
+
require 'rspec/expectations'
|
|
6
|
+
require 'rspec/mocks'
|
|
5
7
|
require "active_model"
|
|
6
8
|
require 'matchers/document'
|
|
7
9
|
require 'matchers/associations'
|
|
8
10
|
require 'matchers/collections'
|
|
9
11
|
require 'matchers/indexes'
|
|
10
12
|
require 'matchers/allow_mass_assignment'
|
|
13
|
+
require 'matchers/accept_nested_attributes'
|
|
11
14
|
require 'matchers/validations'
|
|
15
|
+
require 'matchers/validations/with_message'
|
|
12
16
|
require 'matchers/validations/associated'
|
|
13
17
|
require 'matchers/validations/confirmation_of'
|
|
14
18
|
require 'matchers/validations/exclusion_of'
|
data/mongoid-rspec.gemspec
CHANGED
|
@@ -6,9 +6,9 @@ Gem::Specification.new do |s|
|
|
|
6
6
|
s.name = "mongoid-rspec"
|
|
7
7
|
s.version = Mongoid::Rspec::VERSION
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
|
9
|
-
s.authors = ["Evan Sagge"]
|
|
10
|
-
s.email = %q{evansagge@gmail.com}
|
|
11
|
-
s.homepage = %q{http://github.com/
|
|
9
|
+
s.authors = ["Evan Sagge", "Rodrigo Pinto"]
|
|
10
|
+
s.email = %q{evansagge@gmail.com contato@rodrigopinto.me}
|
|
11
|
+
s.homepage = %q{http://github.com/mongoid-rspec/mongoid-rspec}
|
|
12
12
|
s.summary = %q{RSpec matchers for Mongoid}
|
|
13
13
|
s.description = %q{RSpec matches for Mongoid models, including association and validation matchers}
|
|
14
14
|
|
|
@@ -20,6 +20,6 @@ Gem::Specification.new do |s|
|
|
|
20
20
|
s.require_paths = ["lib"]
|
|
21
21
|
|
|
22
22
|
s.add_dependency 'rake'
|
|
23
|
-
s.add_dependency 'mongoid', '
|
|
24
|
-
s.add_dependency 'rspec',
|
|
23
|
+
s.add_dependency 'mongoid', '~> 4.0.0'
|
|
24
|
+
s.add_dependency 'rspec', '~> 3.1'
|
|
25
25
|
end
|
data/spec/models/article.rb
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
class Article
|
|
2
2
|
include Mongoid::Document
|
|
3
3
|
include Mongoid::Timestamps
|
|
4
|
-
include Mongoid::Paranoia
|
|
5
|
-
include Mongoid::Versioning
|
|
6
|
-
include Mongoid::MultiParameterAttributes
|
|
7
4
|
|
|
8
|
-
field :title
|
|
5
|
+
field :title, localize: true
|
|
9
6
|
field :content
|
|
10
|
-
field :published, :
|
|
11
|
-
field :allow_comments, :
|
|
7
|
+
field :published, type: Boolean, default: false
|
|
8
|
+
field :allow_comments, type: Boolean, default: true
|
|
9
|
+
field :number_of_comments, type: Integer
|
|
10
|
+
field :status, type: Symbol
|
|
12
11
|
|
|
13
|
-
embeds_many :comments
|
|
12
|
+
embeds_many :comments, cascade_callbacks: true
|
|
14
13
|
embeds_one :permalink
|
|
15
|
-
belongs_to :author, :
|
|
14
|
+
belongs_to :author, class_name: 'User', inverse_of: :articles, index: true
|
|
16
15
|
|
|
17
|
-
validates :title, :
|
|
16
|
+
validates :title, presence: true
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
validates_inclusion_of :status, in: [:pending], on: :create
|
|
19
|
+
validates_inclusion_of :status, in: [:approved, :rejected ], on: :update
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
validates_length_of :title, within: 8..16
|
|
22
|
+
validates_length_of :content, minimum: 200
|
|
23
|
+
|
|
24
|
+
index({ title: 1 }, { unique: true, background: true, drop_dups: true })
|
|
22
25
|
index({ published: 1 })
|
|
23
|
-
|
|
26
|
+
index({ 'permalink._id' => 1 })
|
|
27
|
+
|
|
28
|
+
accepts_nested_attributes_for :permalink
|
|
29
|
+
end
|
data/spec/models/comment.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
class MovieArticle < Article
|
|
2
|
-
|
|
3
|
-
field :
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
|
|
3
|
+
field :rating, type: Float
|
|
4
|
+
field :classification, type: Integer
|
|
5
|
+
|
|
6
|
+
validates :rating, numericality: { greater_than: 0, less_than_or_equal_to: 5 }
|
|
7
|
+
validates :classification, numericality: { even: true, only_integer: true, allow_nil: false }
|
|
7
8
|
end
|
data/spec/models/permalink.rb
CHANGED
data/spec/models/person.rb
CHANGED
data/spec/models/profile.rb
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
class Profile
|
|
2
2
|
include Mongoid::Document
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
field :first_name
|
|
5
5
|
field :last_name
|
|
6
6
|
field :age
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
field :hobbies, type: Array, default: []
|
|
8
|
+
|
|
9
|
+
embedded_in :user, inverse_of: :profile
|
|
10
|
+
|
|
11
|
+
validates :age, numericality: { greater_than: 0 }
|
|
12
|
+
validates :terms_of_service, acceptance: true
|
|
13
|
+
validates :hobbies, length: { minimum: 1, message: "requires at least one hobby" }
|
|
12
14
|
|
|
13
|
-
index({first_name: 1, last_name: 1 })
|
|
15
|
+
index({ first_name: 1, last_name: 1 })
|
|
14
16
|
end
|
data/spec/models/record.rb
CHANGED
data/spec/models/site.rb
CHANGED
data/spec/models/user.rb
CHANGED
|
@@ -10,25 +10,25 @@ class User
|
|
|
10
10
|
field :provider_uid
|
|
11
11
|
field :locale
|
|
12
12
|
|
|
13
|
-
belongs_to :site, :
|
|
14
|
-
has_many :articles, :
|
|
15
|
-
has_many :comments, :
|
|
16
|
-
has_and_belongs_to_many :children, :
|
|
17
|
-
has_one :record
|
|
13
|
+
belongs_to :site, inverse_of: :users
|
|
14
|
+
has_many :articles, foreign_key: :author_id, order: :title
|
|
15
|
+
has_many :comments, dependent: :destroy, autosave: true
|
|
16
|
+
has_and_belongs_to_many :children, class_name: "User"
|
|
17
|
+
has_one :record, autobuild: true
|
|
18
18
|
|
|
19
19
|
embeds_one :profile
|
|
20
20
|
|
|
21
|
-
validates :login, :
|
|
22
|
-
validates :email, :
|
|
23
|
-
validates :role, :
|
|
24
|
-
validates :profile, :
|
|
25
|
-
validates :age, :
|
|
26
|
-
validates :password, :
|
|
21
|
+
validates :login, presence: true, uniqueness: { scope: :site }, format: { with: /\A[\w\-]+\z/ }, exclusion: { in: ["super", "index", "edit"] }
|
|
22
|
+
validates :email, uniqueness: { case_sensitive: false, scope: :site, message: "is already taken" }, confirmation: true
|
|
23
|
+
validates :role, presence: true, inclusion: { in: ["admin", "moderator", "member"] }
|
|
24
|
+
validates :profile, presence: true, associated: true
|
|
25
|
+
validates :age, presence: true, numericality: true, inclusion: { in: 23..42 }, on: [:create, :update]
|
|
26
|
+
validates :password, presence: true, on: [:create, :update]
|
|
27
|
+
validates :password, exclusion: { in: ->(user) { ['password'] } }
|
|
27
28
|
validates :provider_uid, presence: true
|
|
28
|
-
validates :locale, :
|
|
29
|
+
validates :locale, inclusion: { in: ->(user) { [:en, :ru] } }
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
attr_accessible :role, :as => :admin
|
|
31
|
+
accepts_nested_attributes_for :articles, :comments
|
|
32
32
|
|
|
33
33
|
def admin?
|
|
34
34
|
false
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "AcceptsNestedAttributes" do
|
|
4
|
+
describe User do
|
|
5
|
+
it { should accept_nested_attributes_for(:articles) }
|
|
6
|
+
it { should accept_nested_attributes_for(:comments) }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe Article do
|
|
10
|
+
it { should accept_nested_attributes_for(:permalink) }
|
|
11
|
+
end
|
|
12
|
+
end
|