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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +7 -2
  6. data/README.md +227 -152
  7. data/lib/matchers/accept_nested_attributes.rb +67 -0
  8. data/lib/matchers/allow_mass_assignment.rb +1 -0
  9. data/lib/matchers/associations.rb +127 -22
  10. data/lib/matchers/document.rb +31 -2
  11. data/lib/matchers/indexes.rb +48 -15
  12. data/lib/matchers/validations/acceptance_of.rb +2 -2
  13. data/lib/matchers/validations/associated.rb +5 -5
  14. data/lib/matchers/validations/confirmation_of.rb +2 -2
  15. data/lib/matchers/validations/custom_validation_of.rb +2 -19
  16. data/lib/matchers/validations/exclusion_of.rb +8 -1
  17. data/lib/matchers/validations/format_of.rb +21 -21
  18. data/lib/matchers/validations/inclusion_of.rb +13 -13
  19. data/lib/matchers/validations/length_of.rb +66 -19
  20. data/lib/matchers/validations/numericality_of.rb +10 -10
  21. data/lib/matchers/validations/presence_of.rb +2 -2
  22. data/lib/matchers/validations/uniqueness_of.rb +13 -30
  23. data/lib/matchers/validations/with_message.rb +27 -0
  24. data/lib/matchers/validations.rb +18 -3
  25. data/lib/mongoid-rspec/version.rb +1 -1
  26. data/lib/mongoid-rspec.rb +5 -1
  27. data/mongoid-rspec.gemspec +5 -5
  28. data/spec/models/article.rb +18 -12
  29. data/spec/models/comment.rb +2 -2
  30. data/spec/models/movie_article.rb +6 -5
  31. data/spec/models/permalink.rb +1 -1
  32. data/spec/models/person.rb +0 -3
  33. data/spec/models/profile.rb +9 -7
  34. data/spec/models/record.rb +1 -1
  35. data/spec/models/site.rb +2 -3
  36. data/spec/models/user.rb +14 -14
  37. data/spec/unit/accept_nested_attributes_spec.rb +12 -0
  38. data/spec/unit/associations_spec.rb +6 -6
  39. data/spec/unit/document_spec.rb +6 -6
  40. data/spec/unit/indexes_spec.rb +3 -2
  41. data/spec/unit/validations_spec.rb +7 -0
  42. data/spec/validators/ssn_validator.rb +3 -1
  43. metadata +43 -32
  44. data/.rvmrc +0 -1
  45. 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 << " with maximum #{@maximum}" if @maximum
45
- options_desc << " with minimum #{@minimum}" if @minimum
46
- options_desc << " within range #{@within}" if @within
47
- options_desc << " as exactly #{@is}" if @is
48
- super << options_desc.to_sentence
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
- actual = @validator.options[:maximum]
55
- if actual == @maximum
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 #{actual}"
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
- actual = @validator.options[:minimum]
65
- if actual == @minimum
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 #{actual}"
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
- actual = @validator.options
76
- if actual[:minimum] == min && actual[:maximum] == max
77
- @positive_result_message << " with range #{@within.inspect}"
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 << " with range #{(actual[:minimum]..actual[:maximum]).inspect}"
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
- actual = @validator.options[:is]
86
- if actual == @is
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 << " is exactly #{actual}"
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,9 +1,9 @@
1
1
  module Mongoid
2
2
  module Matchers
3
- module Validations
3
+ module Validations
4
4
  def validate_presence_of(field)
5
5
  HaveValidationMatcher.new(field, :presence)
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -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
@@ -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| v.kind.to_s == @type}
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 = "validate #{@type} of #{@field.inspect}"
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 (@options[:on] - validator_on_methods).empty?
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
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Rspec
3
- VERSION = "1.5.3"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  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'
@@ -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/evansagge/mongoid-rspec}
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', '>= 3.0.1'
24
- s.add_dependency 'rspec', '>= 2.9'
23
+ s.add_dependency 'mongoid', '~> 4.0.0'
24
+ s.add_dependency 'rspec', '~> 3.1'
25
25
  end
@@ -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, :type => Boolean, :default => false
11
- field :allow_comments, :type => Boolean, :default => true
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, :class_name => 'User', :inverse_of => :articles, :index => true
14
+ belongs_to :author, class_name: 'User', inverse_of: :articles, index: true
16
15
 
17
- validates :title, :presence => true
16
+ validates :title, presence: true
18
17
 
19
- validates_length_of :title, :minimum => 8, :maximum => 16
18
+ validates_inclusion_of :status, in: [:pending], on: :create
19
+ validates_inclusion_of :status, in: [:approved, :rejected ], on: :update
20
20
 
21
- index({ title: 1 }, { unique: true, background: true })
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
- end
26
+ index({ 'permalink._id' => 1 })
27
+
28
+ accepts_nested_attributes_for :permalink
29
+ end
@@ -1,6 +1,6 @@
1
1
  class Comment
2
2
  include Mongoid::Document
3
3
 
4
- embedded_in :article, :inverse_of => :comments
5
- belongs_to :user, :inverse_of => :comments
4
+ embedded_in :article, inverse_of: :comments, polymorphic: true
5
+ belongs_to :user, inverse_of: :comments
6
6
  end
@@ -1,7 +1,8 @@
1
1
  class MovieArticle < Article
2
- field :rating, :type => Float
3
- field :classification, :type => Integer
4
-
5
- validates_numericality_of :rating, :greater_than => 0, :less_than_or_equal_to => 5
6
- validates_numericality_of :classification, :even => true, :only_integer => true, :allow_nil => false
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
@@ -1,5 +1,5 @@
1
1
  class Permalink
2
2
  include Mongoid::Document
3
3
 
4
- embedded_in :linkable, :inverse_of => :link
4
+ embedded_in :linkable, inverse_of: :link
5
5
  end
@@ -1,13 +1,10 @@
1
1
  require 'ssn_validator.rb'
2
2
 
3
3
  class Person
4
-
5
4
  include Mongoid::Document
6
5
 
7
6
  field :name
8
7
  field :ssn
9
8
 
10
9
  validates :ssn, ssn: true
11
-
12
-
13
10
  end
@@ -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
- embedded_in :user, :inverse_of => :profile
9
-
10
- validates_numericality_of :age, :greater_than => 0
11
- validates_acceptance_of :terms_of_service
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
@@ -1,5 +1,5 @@
1
1
  class Record
2
2
  include Mongoid::Document
3
3
 
4
- belongs_to :user, :inverse_of => :record
4
+ belongs_to :user, inverse_of: :record
5
5
  end
data/spec/models/site.rb CHANGED
@@ -3,8 +3,7 @@ class Site
3
3
 
4
4
  field :name
5
5
 
6
- has_many :users, :inverse_of => :site
7
-
8
- validates :name, :presence => true, :uniqueness => true
6
+ has_many :users, inverse_of: :site, order: :email.desc
9
7
 
8
+ validates :name, presence: true, uniqueness: true
10
9
  end
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, :inverse_of => :users
14
- has_many :articles, :foreign_key => :author_id
15
- has_many :comments, :dependent => :destroy, :autosave => true
16
- has_and_belongs_to_many :children, :class_name => "User"
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, :presence => true, :uniqueness => { :scope => :site }, :format => { :with => /^[\w\-]+$/ }, :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]
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, :inclusion => {:in => lambda { |user| [:en, :ru] } }
29
+ validates :locale, inclusion: { in: ->(user) { [:en, :ru] } }
29
30
 
30
- attr_accessible :login, :email, :age, :password
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