mongoid-paranoia 0.3.0 → 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +1 -0
- data/Gemfile +2 -0
- data/Rakefile +3 -5
- data/gemfiles/mongoid_master.gemfile +2 -1
- data/lib/mongoid/core_ext/builders/nested_attributes/many.rb +32 -0
- data/lib/mongoid/core_ext/relations/embedded/many.rb +53 -0
- data/lib/mongoid/core_ext/validatable/uniqueness.rb +41 -0
- data/lib/mongoid/paranoia.rb +27 -18
- data/lib/mongoid/paranoia/version.rb +1 -1
- data/mongoid-paranoia.gemspec +2 -2
- data/spec/app/models/account.rb +0 -4
- data/spec/app/models/acolyte.rb +1 -1
- data/spec/app/models/address.rb +2 -2
- data/spec/app/models/appointment.rb +1 -1
- data/spec/app/models/article.rb +0 -3
- data/spec/app/models/building.rb +0 -2
- data/spec/app/models/building_address.rb +0 -2
- data/spec/app/models/contractor.rb +0 -2
- data/spec/app/models/dog.rb +1 -1
- data/spec/app/models/drug.rb +0 -2
- data/spec/app/models/event.rb +1 -1
- data/spec/app/models/game.rb +0 -2
- data/spec/app/models/house.rb +1 -2
- data/spec/app/models/item.rb +0 -4
- data/spec/app/models/name.rb +0 -2
- data/spec/app/models/paranoid_post.rb +3 -1
- data/spec/app/models/person.rb +3 -5
- data/spec/app/models/player.rb +2 -2
- data/spec/app/models/post.rb +2 -2
- data/spec/app/models/preference.rb +1 -1
- data/spec/app/models/quiz.rb +0 -3
- data/spec/app/models/registry.rb +1 -1
- data/spec/app/models/symptom.rb +1 -1
- data/spec/app/models/tree.rb +1 -1
- data/spec/app/models/video.rb +1 -5
- data/spec/app/models/wiki_page.rb +0 -2
- data/spec/config/mongoid.yml +0 -5
- data/spec/mongoid/attributes/nested_spec.rb +175 -0
- data/spec/mongoid/criteria/scopable_spec.rb +55 -0
- data/spec/mongoid/paranoia_spec.rb +3 -7
- data/spec/mongoid/scoping_spec.rb +55 -0
- data/spec/mongoid/validatable/uniqueness_spec.rb +62 -0
- data/spec/spec_helper.rb +2 -3
- metadata +33 -31
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8cc35c39d324745e9ac2fd3625d74cc8ee8f1238
|
4
|
+
data.tar.gz: 53e4e5d0f8446ae913890b7d17480b52af0e1e61
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 44901d318bd60903538cc48e7e843cdb4f952eeb510df20ea352a6e259a4eebbb49ff859a9d34509a064e59f3afd8b1405ffb74b725c352f0f0cc072a349a201
|
7
|
+
data.tar.gz: 905096d61a53be6e81448a77a3f5144ece4ca7af67671edd5c39b90179e47d2ab602ed72af0f3666b7d92551593f09474fd365e50fe9820ec62029170f6f5d27
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
module Relations
|
4
|
+
module Builders
|
5
|
+
module NestedAttributes
|
6
|
+
class Many < NestedBuilder
|
7
|
+
|
8
|
+
# Destroy the child document, needs to do some checking for embedded
|
9
|
+
# relations and delay the destroy in case parent validation fails.
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
# @example Destroy the child.
|
14
|
+
# builder.destroy(parent, relation, doc)
|
15
|
+
#
|
16
|
+
# @param [ Document ] parent The parent document.
|
17
|
+
# @param [ Proxy ] relation The relation proxy.
|
18
|
+
# @param [ Document ] doc The doc to destroy.
|
19
|
+
#
|
20
|
+
# @since 3.0.10
|
21
|
+
def destroy(parent, relation, doc)
|
22
|
+
if doc.respond_to?(:paranoid?)
|
23
|
+
destroy_document(relation, doc)
|
24
|
+
else
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
module Relations
|
4
|
+
module Embedded
|
5
|
+
class Many < Relations::Many
|
6
|
+
|
7
|
+
# Delete the supplied document from the target. This method is proxied
|
8
|
+
# in order to reindex the array after the operation occurs.
|
9
|
+
#
|
10
|
+
# @example Delete the document from the relation.
|
11
|
+
# person.addresses.delete(address)
|
12
|
+
#
|
13
|
+
# @param [ Document ] document The document to be deleted.
|
14
|
+
#
|
15
|
+
# @return [ Document, nil ] The deleted document or nil if nothing deleted.
|
16
|
+
#
|
17
|
+
# @since 2.0.0.rc.1
|
18
|
+
def delete(document)
|
19
|
+
execute_callback :before_remove, document
|
20
|
+
doc = target.delete_one(document)
|
21
|
+
if doc && !_binding?
|
22
|
+
_unscoped.delete_one(doc) unless doc.respond_to?(:paranoid?)
|
23
|
+
if _assigning?
|
24
|
+
if doc.respond_to?(:paranoid?)
|
25
|
+
doc.destroy(suppress: true)
|
26
|
+
else
|
27
|
+
base.add_atomic_pull(doc)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
doc.delete(suppress: true)
|
31
|
+
unbind_one(doc)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
reindex
|
35
|
+
execute_callback :after_remove, document
|
36
|
+
doc
|
37
|
+
end
|
38
|
+
|
39
|
+
# For use only with Mongoid::Paranoia - will be removed in 4.0.
|
40
|
+
#
|
41
|
+
# @example Get the deleted documents from the relation.
|
42
|
+
# person.paranoid_phones.deleted
|
43
|
+
#
|
44
|
+
# @return [ Criteria ] The deleted documents.
|
45
|
+
#
|
46
|
+
# @since 3.0.10
|
47
|
+
def deleted
|
48
|
+
unscoped.deleted
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
module Validatable
|
4
|
+
|
5
|
+
# Validates whether or not a field is unique against the documents in the
|
6
|
+
# database.
|
7
|
+
#
|
8
|
+
# @example Define the uniqueness validator.
|
9
|
+
#
|
10
|
+
# class Person
|
11
|
+
# include Mongoid::Document
|
12
|
+
# field :title
|
13
|
+
#
|
14
|
+
# validates_uniqueness_of :title
|
15
|
+
# end
|
16
|
+
class UniquenessValidator < ActiveModel::EachValidator
|
17
|
+
|
18
|
+
# Scope the criteria to the scope options provided.
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
# @example Scope the criteria.
|
23
|
+
# validator.scope(criteria, document)
|
24
|
+
#
|
25
|
+
# @param [ Criteria ] criteria The criteria to scope.
|
26
|
+
# @param [ Document ] document The document being validated.
|
27
|
+
#
|
28
|
+
# @return [ Criteria ] The scoped criteria.
|
29
|
+
#
|
30
|
+
# @since 2.3.0
|
31
|
+
def scope(criteria, document, attribute)
|
32
|
+
Array.wrap(options[:scope]).each do |item|
|
33
|
+
name = document.database_field_name(item)
|
34
|
+
criteria = criteria.where(item => document.attributes[name])
|
35
|
+
end
|
36
|
+
criteria = criteria.where(deleted_at: nil) if document.respond_to?(:paranoid?)
|
37
|
+
criteria
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/mongoid/paranoia.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'mongoid/core_ext/builders/nested_attributes/many'
|
2
|
+
require 'mongoid/core_ext/relations/embedded/many'
|
3
|
+
require 'mongoid/core_ext/validatable/uniqueness'
|
4
|
+
|
1
5
|
# encoding: utf-8
|
2
6
|
module Mongoid
|
3
7
|
|
@@ -11,14 +15,16 @@ module Mongoid
|
|
11
15
|
# include Mongoid::Paranoia
|
12
16
|
# end
|
13
17
|
module Paranoia
|
18
|
+
include Mongoid::Persistable::Deletable
|
14
19
|
extend ActiveSupport::Concern
|
15
20
|
|
16
21
|
included do
|
17
22
|
field :deleted_at, type: Time
|
23
|
+
class_attribute :paranoid
|
18
24
|
self.paranoid = true
|
19
25
|
|
20
|
-
default_scope where(deleted_at: nil)
|
21
|
-
scope :deleted, ne(deleted_at: nil)
|
26
|
+
default_scope ->{ where(deleted_at: nil) }
|
27
|
+
scope :deleted, ->{ ne(deleted_at: nil) }
|
22
28
|
end
|
23
29
|
|
24
30
|
# Delete the paranoid +Document+ from the database completely. This will
|
@@ -34,18 +40,6 @@ module Mongoid
|
|
34
40
|
run_callbacks(:destroy) { delete! }
|
35
41
|
end
|
36
42
|
|
37
|
-
# Delete the paranoid +Document+ from the database completely.
|
38
|
-
#
|
39
|
-
# @example Hard delete the document.
|
40
|
-
# document.delete!
|
41
|
-
#
|
42
|
-
# @return [ true, false ] If the operation succeeded.
|
43
|
-
#
|
44
|
-
# @since 1.0.0
|
45
|
-
def delete!
|
46
|
-
Persistence::Operations.remove(self).persist
|
47
|
-
end
|
48
|
-
|
49
43
|
# Delete the +Document+, will set the deleted_at timestamp and not actually
|
50
44
|
# delete it.
|
51
45
|
#
|
@@ -57,17 +51,28 @@ module Mongoid
|
|
57
51
|
# @return [ true ] True.
|
58
52
|
#
|
59
53
|
# @since 1.0.0
|
60
|
-
def
|
54
|
+
def remove_with_paranoia(options = {})
|
61
55
|
cascade!
|
62
56
|
time = self.deleted_at = Time.now
|
63
57
|
paranoid_collection.find(atomic_selector).
|
64
58
|
update({ "$set" => { paranoid_field => time }})
|
65
59
|
@destroyed = true
|
66
|
-
IdentityMap.remove(self)
|
67
|
-
clear_timeless_option
|
68
60
|
true
|
69
61
|
end
|
70
|
-
|
62
|
+
alias_method_chain :remove, :paranoia
|
63
|
+
alias :delete :remove_with_paranoia
|
64
|
+
|
65
|
+
# Delete the paranoid +Document+ from the database completely.
|
66
|
+
#
|
67
|
+
# @example Hard delete the document.
|
68
|
+
# document.delete!
|
69
|
+
#
|
70
|
+
# @return [ true, false ] If the operation succeeded.
|
71
|
+
#
|
72
|
+
# @since 1.0.0
|
73
|
+
def delete!
|
74
|
+
remove_without_paranoia
|
75
|
+
end
|
71
76
|
|
72
77
|
# Determines if this document is destroyed.
|
73
78
|
#
|
@@ -82,6 +87,10 @@ module Mongoid
|
|
82
87
|
end
|
83
88
|
alias :deleted? :destroyed?
|
84
89
|
|
90
|
+
def persisted?
|
91
|
+
!new_record? && !(@destroyed ||= false)
|
92
|
+
end
|
93
|
+
|
85
94
|
# Restores a previously soft-deleted document. Handles this by removing the
|
86
95
|
# deleted_at flag.
|
87
96
|
#
|
data/mongoid-paranoia.gemspec
CHANGED
@@ -13,6 +13,6 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.files = `git ls-files`.split("\n")
|
14
14
|
gem.require_path = 'lib'
|
15
15
|
|
16
|
-
gem.add_dependency 'activesupport'
|
17
|
-
gem.add_dependency 'mongoid', '
|
16
|
+
gem.add_dependency 'activesupport'
|
17
|
+
gem.add_dependency 'mongoid', '4.0.0.beta1'
|
18
18
|
end
|
data/spec/app/models/account.rb
CHANGED
@@ -18,10 +18,6 @@ class Account
|
|
18
18
|
has_and_belongs_to_many :agents
|
19
19
|
has_one :comment, validate: false
|
20
20
|
|
21
|
-
attr_accessible :nickname, as: [ :default, :admin ]
|
22
|
-
attr_accessible :name, as: [ :default, :admin ]
|
23
|
-
attr_accessible :balance, as: :default
|
24
|
-
|
25
21
|
validates_presence_of :name
|
26
22
|
validates_presence_of :nickname, on: :upsert
|
27
23
|
validates_length_of :name, maximum: 10, on: :create
|
data/spec/app/models/acolyte.rb
CHANGED
data/spec/app/models/address.rb
CHANGED
@@ -38,8 +38,8 @@ class Address
|
|
38
38
|
belongs_to :account
|
39
39
|
belongs_to :band
|
40
40
|
|
41
|
-
scope :without_postcode, where(postcode: nil)
|
42
|
-
scope :rodeo, where(street: "Rodeo Dr") do
|
41
|
+
scope :without_postcode, ->{ where(postcode: nil) }
|
42
|
+
scope :rodeo, ->{ where(street: "Rodeo Dr") } do
|
43
43
|
def mansion?
|
44
44
|
all? { |address| address.street == "Rodeo Dr" }
|
45
45
|
end
|
data/spec/app/models/article.rb
CHANGED
@@ -5,9 +5,6 @@ class Article
|
|
5
5
|
field :is_rss, type: Boolean, default: false
|
6
6
|
field :user_login, type: String
|
7
7
|
|
8
|
-
attr_accessible :title, as: [:default, :parser]
|
9
|
-
attr_accessible :is_rss, as: :parser
|
10
|
-
attr_accessible :user_login
|
11
8
|
has_and_belongs_to_many :tags, validate: false
|
12
9
|
has_and_belongs_to_many :preferences, inverse_of: nil, validate: false
|
13
10
|
end
|
data/spec/app/models/building.rb
CHANGED
data/spec/app/models/dog.rb
CHANGED
data/spec/app/models/drug.rb
CHANGED
data/spec/app/models/event.rb
CHANGED
data/spec/app/models/game.rb
CHANGED
data/spec/app/models/house.rb
CHANGED
data/spec/app/models/item.rb
CHANGED
@@ -3,10 +3,6 @@ class Item
|
|
3
3
|
field :title, type: String
|
4
4
|
field :is_rss, type: Boolean, default: false
|
5
5
|
field :user_login, type: String
|
6
|
-
|
7
|
-
attr_protected :title, as: [:default, :parser]
|
8
|
-
attr_protected :is_rss, as: :parser
|
9
|
-
attr_protected :user_login
|
10
6
|
end
|
11
7
|
|
12
8
|
require "app/models/sub_item"
|
data/spec/app/models/name.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'mongoid/versioning'
|
2
|
+
|
1
3
|
class ParanoidPost
|
2
4
|
include Mongoid::Document
|
3
5
|
include Mongoid::Versioning
|
@@ -15,7 +17,7 @@ class ParanoidPost
|
|
15
17
|
has_many :authors, dependent: :delete
|
16
18
|
has_many :titles, dependent: :restrict
|
17
19
|
|
18
|
-
scope :recent, where(created_at: { "$lt" => Time.now, "$gt" => 30.days.ago })
|
20
|
+
scope :recent, ->{ where(created_at: { "$lt" => Time.now, "$gt" => 30.days.ago }) }
|
19
21
|
|
20
22
|
before_destroy :before_destroy_stub
|
21
23
|
after_destroy :after_destroy_stub
|
data/spec/app/models/person.rb
CHANGED
@@ -23,7 +23,7 @@ class Person
|
|
23
23
|
field :owner_id, type: Integer
|
24
24
|
field :security_code
|
25
25
|
field :reading, type: Object
|
26
|
-
field :bson_id, type:
|
26
|
+
field :bson_id, type: BSON::ObjectId
|
27
27
|
field :pattern, type: Regexp
|
28
28
|
field :override_me, type: Integer
|
29
29
|
field :t, as: :test, type: String
|
@@ -41,8 +41,6 @@ class Person
|
|
41
41
|
|
42
42
|
attr_reader :rescored
|
43
43
|
|
44
|
-
attr_protected :security_code, :owner_id, :appointments
|
45
|
-
|
46
44
|
embeds_many :favorites, order: :title.desc, inverse_of: :perp, validate: false
|
47
45
|
embeds_many :videos, order: [[ :title, :asc ]], validate: false
|
48
46
|
embeds_many :phone_numbers, class_name: "Phone", validate: false
|
@@ -123,8 +121,8 @@ class Person
|
|
123
121
|
accepts_nested_attributes_for :quiz
|
124
122
|
accepts_nested_attributes_for :services, allow_destroy: true
|
125
123
|
|
126
|
-
scope :minor, where(:age.lt => 18)
|
127
|
-
scope :without_ssn, without(:ssn)
|
124
|
+
scope :minor, ->{ where(:age.lt => 18) }
|
125
|
+
scope :without_ssn, ->{ without(:ssn) }
|
128
126
|
scope :search, ->(query){ any_of({ title: query }) }
|
129
127
|
|
130
128
|
def score_with_rescoring=(score)
|
data/spec/app/models/player.rb
CHANGED
@@ -6,13 +6,13 @@ class Player
|
|
6
6
|
field :impressions, type: Integer, default: 0
|
7
7
|
field :status
|
8
8
|
|
9
|
-
scope :active, where(active: true) do
|
9
|
+
scope :active, ->{ where(active: true) } do
|
10
10
|
def extension
|
11
11
|
"extension"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
scope :inactive, where(active: false)
|
15
|
+
scope :inactive, ->{ where(active: false) }
|
16
16
|
scope :frags_over, ->(count) { where(:frags.gt => count) }
|
17
17
|
scope :deaths_under, ->(count) { where(:deaths.lt => count) }
|
18
18
|
scope :deaths_over, ->(count) { where(:deaths.gt => count) }
|
data/spec/app/models/post.rb
CHANGED
@@ -13,8 +13,8 @@ class Post
|
|
13
13
|
has_and_belongs_to_many :tags, before_add: :before_add_tag, after_add: :after_add_tag, before_remove: :before_remove_tag, after_remove: :after_remove_tag
|
14
14
|
has_many :videos, validate: false
|
15
15
|
|
16
|
-
scope :recent, where(created_at: { "$lt" => Time.now, "$gt" => 30.days.ago })
|
17
|
-
scope :posting, where(:content.in => [ "Posting" ])
|
16
|
+
scope :recent, ->{ where(created_at: { "$lt" => Time.now, "$gt" => 30.days.ago }) }
|
17
|
+
scope :posting, ->{ where(:content.in => [ "Posting" ]) }
|
18
18
|
|
19
19
|
validates_format_of :title, without: /\$\$\$/
|
20
20
|
|
@@ -5,5 +5,5 @@ class Preference
|
|
5
5
|
field :ranking, type: Integer
|
6
6
|
has_and_belongs_to_many :people, validate: false
|
7
7
|
validates_length_of :name, minimum: 2, allow_nil: true
|
8
|
-
scope :posting, where(:value.in => [ "Posting" ])
|
8
|
+
scope :posting, ->{ where(:value.in => [ "Posting" ]) }
|
9
9
|
end
|
data/spec/app/models/quiz.rb
CHANGED
data/spec/app/models/registry.rb
CHANGED
data/spec/app/models/symptom.rb
CHANGED
data/spec/app/models/tree.rb
CHANGED
data/spec/app/models/video.rb
CHANGED
@@ -9,9 +9,5 @@ class Video
|
|
9
9
|
belongs_to :post
|
10
10
|
belongs_to :game
|
11
11
|
|
12
|
-
default_scope asc(:title)
|
13
|
-
|
14
|
-
attr_accessible :title, as: [ :default, :admin ]
|
15
|
-
attr_accessible :year, as: [ :default ]
|
16
|
-
attr_accessible :person_attributes, as: [ :default ]
|
12
|
+
default_scope ->{ asc(:title) }
|
17
13
|
end
|
@@ -9,8 +9,6 @@ class WikiPage
|
|
9
9
|
field :description, type: String, localize: true
|
10
10
|
max_versions 5
|
11
11
|
|
12
|
-
attr_protected :author
|
13
|
-
|
14
12
|
has_many :comments, dependent: :destroy, validate: false
|
15
13
|
has_many :child_pages, class_name: "WikiPage", dependent: :delete, inverse_of: :parent_pages
|
16
14
|
belongs_to :parent_pages, class_name: "WikiPage", inverse_of: :child_pages
|
data/spec/config/mongoid.yml
CHANGED
@@ -4,8 +4,6 @@ test:
|
|
4
4
|
database: mongoid_test
|
5
5
|
hosts:
|
6
6
|
- <%=ENV["MONGOID_SPEC_HOST"]%>:<%=ENV["MONGOID_SPEC_PORT"]%>
|
7
|
-
options:
|
8
|
-
consistency: :strong
|
9
7
|
mongohq_single:
|
10
8
|
database: <%=ENV["MONGOHQ_SINGLE_NAME"]%>
|
11
9
|
username: <%=ENV["MONGOHQ_SINGLE_USER"]%>
|
@@ -14,7 +12,6 @@ test:
|
|
14
12
|
- <%=ENV["MONGOHQ_SINGLE_URL"]%>
|
15
13
|
options:
|
16
14
|
safe: true
|
17
|
-
consistency: :strong
|
18
15
|
mongohq_repl:
|
19
16
|
database: <%=ENV["MONGOHQ_REPL_NAME"]%>
|
20
17
|
username: <%=ENV["MONGOHQ_REPL_USER"]%>
|
@@ -23,13 +20,11 @@ test:
|
|
23
20
|
- <%=ENV["MONGOHQ_REPL_1_URL"]%>
|
24
21
|
- <%=ENV["MONGOHQ_REPL_2_URL"]%>
|
25
22
|
options:
|
26
|
-
consistency: :strong
|
27
23
|
safe: true
|
28
24
|
mongohq_repl_uri:
|
29
25
|
uri: <%= ENV["MONGOHQ_REPL_URI"]%>
|
30
26
|
options:
|
31
27
|
allow_dynamic_fields: true
|
32
|
-
identity_map_enabled: false
|
33
28
|
include_root_in_json: false
|
34
29
|
include_type_for_serialization: false
|
35
30
|
preload_models: false
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Attributes::Nested do
|
4
|
+
|
5
|
+
describe "##{name}_attributes=" do
|
6
|
+
|
7
|
+
context "when the parent document is new" do
|
8
|
+
|
9
|
+
context "when the relation is an embeds many" do
|
10
|
+
|
11
|
+
let(:person) do
|
12
|
+
Person.new
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:address_one) do
|
16
|
+
Address.new(street: "Unter den Linden")
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:address_two) do
|
20
|
+
Address.new(street: "Kurfeurstendamm")
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:phone_one) do
|
24
|
+
ParanoidPhone.new(number: "1")
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:phone_two) do
|
28
|
+
ParanoidPhone.new(number: "2")
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when ids are passed" do
|
32
|
+
|
33
|
+
before do
|
34
|
+
person.addresses << [ address_one, address_two ]
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when destroy attributes are passed" do
|
38
|
+
|
39
|
+
context "when the ids match" do
|
40
|
+
|
41
|
+
context "when allow_destroy is true" do
|
42
|
+
|
43
|
+
context "when the child has defaults" do
|
44
|
+
|
45
|
+
before(:all) do
|
46
|
+
Person.accepts_nested_attributes_for :appointments, allow_destroy: true
|
47
|
+
end
|
48
|
+
|
49
|
+
after(:all) do
|
50
|
+
Person.send(:undef_method, :appointments_attributes=)
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when the parent is persisted" do
|
54
|
+
|
55
|
+
let!(:persisted) do
|
56
|
+
Person.create(age: 42)
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when the child returns false in a before callback" do
|
60
|
+
|
61
|
+
context "when the child is paranoid" do
|
62
|
+
|
63
|
+
before(:all) do
|
64
|
+
Person.accepts_nested_attributes_for :paranoid_phones, allow_destroy: true
|
65
|
+
end
|
66
|
+
|
67
|
+
after(:all) do
|
68
|
+
Person.send(:undef_method, :paranoid_phones=)
|
69
|
+
Person.accepts_nested_attributes_for :paranoid_phones
|
70
|
+
end
|
71
|
+
|
72
|
+
let!(:phone) do
|
73
|
+
persisted.paranoid_phones.create
|
74
|
+
end
|
75
|
+
|
76
|
+
before do
|
77
|
+
persisted.paranoid_phones_attributes =
|
78
|
+
{ "foo" => { "id" => phone.id, "number" => 42, "_destroy" => true }}
|
79
|
+
end
|
80
|
+
|
81
|
+
it "does not destroy the child" do
|
82
|
+
persisted.reload.paranoid_phones.should_not be_empty
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when the child is paranoid" do
|
90
|
+
|
91
|
+
before(:all) do
|
92
|
+
Person.send(:undef_method, :paranoid_phones_attributes=)
|
93
|
+
Person.accepts_nested_attributes_for :paranoid_phones,
|
94
|
+
allow_destroy: true
|
95
|
+
end
|
96
|
+
|
97
|
+
after(:all) do
|
98
|
+
Person.send(:undef_method, :paranoid_phones_attributes=)
|
99
|
+
Person.accepts_nested_attributes_for :paranoid_phones
|
100
|
+
end
|
101
|
+
|
102
|
+
[ 1, "1", true, "true" ].each do |truth|
|
103
|
+
|
104
|
+
context "when passed a #{truth} with destroy" do
|
105
|
+
|
106
|
+
context "when the parent is persisted" do
|
107
|
+
|
108
|
+
let!(:persisted) do
|
109
|
+
Person.create do |p|
|
110
|
+
p.paranoid_phones << [ phone_one, phone_two ]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "when setting, pulling, and pushing in one op" do
|
115
|
+
|
116
|
+
before do
|
117
|
+
persisted.paranoid_phones_attributes =
|
118
|
+
{
|
119
|
+
"bar" => { "id" => phone_one.id, "_destroy" => truth },
|
120
|
+
"foo" => { "id" => phone_two.id, "number" => "3" },
|
121
|
+
"baz" => { "number" => "4" }
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
it "removes the first document from the relation" do
|
126
|
+
persisted.paranoid_phones.size.should eq(2)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "does not delete the unmarked document" do
|
130
|
+
persisted.paranoid_phones.first.number.should eq("3")
|
131
|
+
end
|
132
|
+
|
133
|
+
it "adds the new document to the relation" do
|
134
|
+
persisted.paranoid_phones.last.number.should eq("4")
|
135
|
+
end
|
136
|
+
|
137
|
+
it "has the proper persisted count" do
|
138
|
+
persisted.paranoid_phones.count.should eq(1)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "soft deletes the removed document" do
|
142
|
+
phone_one.should be_destroyed
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when saving the parent" do
|
146
|
+
|
147
|
+
before do
|
148
|
+
persisted.with(safe: true).save
|
149
|
+
end
|
150
|
+
|
151
|
+
it "deletes the marked document from the relation" do
|
152
|
+
persisted.reload.paranoid_phones.count.should eq(2)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "does not delete the unmarked document" do
|
156
|
+
persisted.reload.paranoid_phones.first.number.should eq("3")
|
157
|
+
end
|
158
|
+
|
159
|
+
it "persists the new document to the relation" do
|
160
|
+
persisted.reload.paranoid_phones.last.number.should eq("4")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Criteria::Scopable do
|
4
|
+
|
5
|
+
context "when the document is paranoid" do
|
6
|
+
|
7
|
+
context "when calling a class method" do
|
8
|
+
|
9
|
+
let(:criteria) do
|
10
|
+
Fish.fresh
|
11
|
+
end
|
12
|
+
|
13
|
+
it "includes the deleted_at criteria in the selector" do
|
14
|
+
criteria.selector.should eq({
|
15
|
+
"deleted_at" => nil, "fresh" => true
|
16
|
+
})
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when chaining a class method to unscoped" do
|
21
|
+
|
22
|
+
let(:criteria) do
|
23
|
+
Fish.unscoped.fresh
|
24
|
+
end
|
25
|
+
|
26
|
+
it "does not include the deleted_at in the selector" do
|
27
|
+
criteria.selector.should eq({ "fresh" => true })
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when chaining a class method to deleted" do
|
32
|
+
|
33
|
+
let(:criteria) do
|
34
|
+
Fish.deleted.fresh
|
35
|
+
end
|
36
|
+
|
37
|
+
it "includes the deleted_at $ne criteria in the selector" do
|
38
|
+
criteria.selector.should eq({
|
39
|
+
"deleted_at" => { "$ne" => nil }, "fresh" => true
|
40
|
+
})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when chaining a where to unscoped" do
|
45
|
+
|
46
|
+
let(:criteria) do
|
47
|
+
Fish.unscoped.where(fresh: true)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "includes no default scoping information in the selector" do
|
51
|
+
criteria.selector.should eq({ "fresh" => true })
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -46,7 +46,7 @@ describe Mongoid::Paranoia do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "returns the deleted documents" do
|
49
|
-
person.paranoid_phones.deleted.should eq([ phone ])
|
49
|
+
person.paranoid_phones.deleted.to_a.should eq([ phone ])
|
50
50
|
end
|
51
51
|
|
52
52
|
it "returns the correct count" do
|
@@ -480,11 +480,7 @@ describe Mongoid::Paranoia do
|
|
480
480
|
end
|
481
481
|
|
482
482
|
it "clears out the persistence options" do
|
483
|
-
|
484
|
-
end
|
485
|
-
|
486
|
-
it "clears out the identity map" do
|
487
|
-
Mongoid::IdentityMap.should be_empty
|
483
|
+
ParanoidPost.persistence_options.should be_nil
|
488
484
|
end
|
489
485
|
end
|
490
486
|
|
@@ -657,7 +653,7 @@ describe Mongoid::Paranoia do
|
|
657
653
|
end
|
658
654
|
|
659
655
|
before do
|
660
|
-
post.set(:
|
656
|
+
post.set(deleted_at: time)
|
661
657
|
end
|
662
658
|
|
663
659
|
it "persists the change" do
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Criteria::Scopable do
|
4
|
+
|
5
|
+
context "when the document is paranoid" do
|
6
|
+
|
7
|
+
context "when calling a class method" do
|
8
|
+
|
9
|
+
let(:criteria) do
|
10
|
+
Fish.fresh
|
11
|
+
end
|
12
|
+
|
13
|
+
it "includes the deleted_at criteria in the selector" do
|
14
|
+
criteria.selector.should eq({
|
15
|
+
"deleted_at" => nil, "fresh" => true
|
16
|
+
})
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when chaining a class method to unscoped" do
|
21
|
+
|
22
|
+
let(:criteria) do
|
23
|
+
Fish.unscoped.fresh
|
24
|
+
end
|
25
|
+
|
26
|
+
it "does not include the deleted_at in the selector" do
|
27
|
+
criteria.selector.should eq({ "fresh" => true })
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when chaining a class method to deleted" do
|
32
|
+
|
33
|
+
let(:criteria) do
|
34
|
+
Fish.deleted.fresh
|
35
|
+
end
|
36
|
+
|
37
|
+
it "includes the deleted_at $ne criteria in the selector" do
|
38
|
+
criteria.selector.should eq({
|
39
|
+
"deleted_at" => { "$ne" => nil }, "fresh" => true
|
40
|
+
})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when chaining a where to unscoped" do
|
45
|
+
|
46
|
+
let(:criteria) do
|
47
|
+
Fish.unscoped.where(fresh: true)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "includes no default scoping information in the selector" do
|
51
|
+
criteria.selector.should eq({ "fresh" => true })
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Validatable::UniquenessValidator do
|
4
|
+
|
5
|
+
describe "#valid?" do
|
6
|
+
|
7
|
+
context "when the document is a root document" do
|
8
|
+
|
9
|
+
context "when the document is paranoid" do
|
10
|
+
|
11
|
+
before do
|
12
|
+
ParanoidPost.validates_uniqueness_of :title
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
ParanoidPost.reset_callbacks(:validate)
|
17
|
+
end
|
18
|
+
|
19
|
+
let!(:post) do
|
20
|
+
ParanoidPost.create(title: "testing")
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when the field is unique" do
|
24
|
+
|
25
|
+
let(:new_post) do
|
26
|
+
ParanoidPost.new(title: "test")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns true" do
|
30
|
+
new_post.should be_valid
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when the field is unique for non soft deleted docs" do
|
35
|
+
|
36
|
+
before do
|
37
|
+
post.delete
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:new_post) do
|
41
|
+
ParanoidPost.new(title: "testing")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns true" do
|
45
|
+
new_post.should be_valid
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when the field is not unique" do
|
50
|
+
|
51
|
+
let(:new_post) do
|
52
|
+
ParanoidPost.new(title: "testing")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns false" do
|
56
|
+
new_post.should_not be_valid
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -36,7 +36,7 @@ end
|
|
36
36
|
|
37
37
|
# Set the database that the spec suite connects to.
|
38
38
|
Mongoid.configure do |config|
|
39
|
-
config.connect_to(database_id
|
39
|
+
config.connect_to(database_id)
|
40
40
|
end
|
41
41
|
|
42
42
|
# Autoload every model for the test suite that sits in spec/app/models.
|
@@ -57,10 +57,9 @@ end
|
|
57
57
|
|
58
58
|
RSpec.configure do |config|
|
59
59
|
|
60
|
-
# Drop all collections
|
60
|
+
# Drop all collections before each spec.
|
61
61
|
config.before(:each) do
|
62
62
|
Mongoid.purge!
|
63
|
-
Mongoid::IdentityMap.clear
|
64
63
|
end
|
65
64
|
|
66
65
|
# On travis we are creating many different databases on each test run. We
|
metadata
CHANGED
@@ -1,48 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-paranoia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.3.0
|
4
|
+
version: 1.0.0.beta1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Mario Uher
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-04-09 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
prerelease: false
|
16
|
-
version_requirements: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - ! '>='
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '3.0'
|
21
|
-
none: false
|
22
|
-
type: :runtime
|
23
14
|
name: activesupport
|
24
15
|
requirement: !ruby/object:Gem::Requirement
|
25
16
|
requirements:
|
26
|
-
- -
|
17
|
+
- - ">="
|
27
18
|
- !ruby/object:Gem::Version
|
28
|
-
version: '
|
29
|
-
|
30
|
-
- !ruby/object:Gem::Dependency
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
31
21
|
prerelease: false
|
32
22
|
version_requirements: !ruby/object:Gem::Requirement
|
33
23
|
requirements:
|
34
|
-
- -
|
24
|
+
- - ">="
|
35
25
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
37
|
-
|
38
|
-
type: :runtime
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
39
28
|
name: mongoid
|
40
29
|
requirement: !ruby/object:Gem::Requirement
|
41
30
|
requirements:
|
42
|
-
- -
|
31
|
+
- - '='
|
43
32
|
- !ruby/object:Gem::Version
|
44
|
-
version:
|
45
|
-
|
33
|
+
version: 4.0.0.beta1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.0.0.beta1
|
46
41
|
description: There may be times when you don't want documents to actually get deleted
|
47
42
|
from the database, but "flagged" as deleted.
|
48
43
|
email: uher.mario@gmail.com
|
@@ -50,13 +45,16 @@ executables: []
|
|
50
45
|
extensions: []
|
51
46
|
extra_rdoc_files: []
|
52
47
|
files:
|
53
|
-
- .gitignore
|
54
|
-
- .travis.yml
|
48
|
+
- ".gitignore"
|
49
|
+
- ".travis.yml"
|
55
50
|
- CHANGELOG.md
|
56
51
|
- Gemfile
|
57
52
|
- README.md
|
58
53
|
- Rakefile
|
59
54
|
- gemfiles/mongoid_master.gemfile
|
55
|
+
- lib/mongoid/core_ext/builders/nested_attributes/many.rb
|
56
|
+
- lib/mongoid/core_ext/relations/embedded/many.rb
|
57
|
+
- lib/mongoid/core_ext/validatable/uniqueness.rb
|
60
58
|
- lib/mongoid/paranoia.rb
|
61
59
|
- lib/mongoid/paranoia/version.rb
|
62
60
|
- mongoid-paranoia.gemspec
|
@@ -244,30 +242,34 @@ files:
|
|
244
242
|
- spec/app/models/word_origin.rb
|
245
243
|
- spec/app/models/writer.rb
|
246
244
|
- spec/config/mongoid.yml
|
245
|
+
- spec/mongoid/attributes/nested_spec.rb
|
246
|
+
- spec/mongoid/criteria/scopable_spec.rb
|
247
247
|
- spec/mongoid/paranoia_spec.rb
|
248
|
+
- spec/mongoid/scoping_spec.rb
|
249
|
+
- spec/mongoid/validatable/uniqueness_spec.rb
|
248
250
|
- spec/spec_helper.rb
|
249
251
|
homepage: https://github.com/haihappen/mongoid-paranoia
|
250
252
|
licenses: []
|
253
|
+
metadata: {}
|
251
254
|
post_install_message:
|
252
255
|
rdoc_options: []
|
253
256
|
require_paths:
|
254
257
|
- lib
|
255
258
|
required_ruby_version: !ruby/object:Gem::Requirement
|
256
259
|
requirements:
|
257
|
-
- -
|
260
|
+
- - ">="
|
258
261
|
- !ruby/object:Gem::Version
|
259
262
|
version: '0'
|
260
|
-
none: false
|
261
263
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
262
264
|
requirements:
|
263
|
-
- -
|
265
|
+
- - ">"
|
264
266
|
- !ruby/object:Gem::Version
|
265
|
-
version:
|
266
|
-
none: false
|
267
|
+
version: 1.3.1
|
267
268
|
requirements: []
|
268
269
|
rubyforge_project:
|
269
|
-
rubygems_version:
|
270
|
+
rubygems_version: 2.2.0
|
270
271
|
signing_key:
|
271
|
-
specification_version:
|
272
|
+
specification_version: 4
|
272
273
|
summary: Extraction of mongoid-paranoia into its own gem.
|
273
274
|
test_files: []
|
275
|
+
has_rdoc:
|