mongoid-paranoia 0.3.0 → 1.0.0.beta1
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/.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:
|