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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +1 -0
  3. data/Gemfile +2 -0
  4. data/Rakefile +3 -5
  5. data/gemfiles/mongoid_master.gemfile +2 -1
  6. data/lib/mongoid/core_ext/builders/nested_attributes/many.rb +32 -0
  7. data/lib/mongoid/core_ext/relations/embedded/many.rb +53 -0
  8. data/lib/mongoid/core_ext/validatable/uniqueness.rb +41 -0
  9. data/lib/mongoid/paranoia.rb +27 -18
  10. data/lib/mongoid/paranoia/version.rb +1 -1
  11. data/mongoid-paranoia.gemspec +2 -2
  12. data/spec/app/models/account.rb +0 -4
  13. data/spec/app/models/acolyte.rb +1 -1
  14. data/spec/app/models/address.rb +2 -2
  15. data/spec/app/models/appointment.rb +1 -1
  16. data/spec/app/models/article.rb +0 -3
  17. data/spec/app/models/building.rb +0 -2
  18. data/spec/app/models/building_address.rb +0 -2
  19. data/spec/app/models/contractor.rb +0 -2
  20. data/spec/app/models/dog.rb +1 -1
  21. data/spec/app/models/drug.rb +0 -2
  22. data/spec/app/models/event.rb +1 -1
  23. data/spec/app/models/game.rb +0 -2
  24. data/spec/app/models/house.rb +1 -2
  25. data/spec/app/models/item.rb +0 -4
  26. data/spec/app/models/name.rb +0 -2
  27. data/spec/app/models/paranoid_post.rb +3 -1
  28. data/spec/app/models/person.rb +3 -5
  29. data/spec/app/models/player.rb +2 -2
  30. data/spec/app/models/post.rb +2 -2
  31. data/spec/app/models/preference.rb +1 -1
  32. data/spec/app/models/quiz.rb +0 -3
  33. data/spec/app/models/registry.rb +1 -1
  34. data/spec/app/models/symptom.rb +1 -1
  35. data/spec/app/models/tree.rb +1 -1
  36. data/spec/app/models/video.rb +1 -5
  37. data/spec/app/models/wiki_page.rb +0 -2
  38. data/spec/config/mongoid.yml +0 -5
  39. data/spec/mongoid/attributes/nested_spec.rb +175 -0
  40. data/spec/mongoid/criteria/scopable_spec.rb +55 -0
  41. data/spec/mongoid/paranoia_spec.rb +3 -7
  42. data/spec/mongoid/scoping_spec.rb +55 -0
  43. data/spec/mongoid/validatable/uniqueness_spec.rb +62 -0
  44. data/spec/spec_helper.rb +2 -3
  45. 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
@@ -3,6 +3,7 @@ language: ruby
3
3
  rvm:
4
4
  - 1.9.3
5
5
  - 2.0.0
6
+ - 2.1.0
6
7
  - ruby-head
7
8
 
8
9
  gemfile:
data/Gemfile CHANGED
@@ -4,3 +4,5 @@ gemspec
4
4
 
5
5
  gem 'rspec'
6
6
  gem 'rake'
7
+
8
+ gem 'mongoid-versioning', '1.0.0.beta1'
data/Rakefile CHANGED
@@ -1,7 +1,5 @@
1
- require 'rake/testtask'
1
+ require 'rspec/core/rake_task'
2
2
 
3
- Rake::TestTask.new do |t|
4
- t.test_files = FileList['spec/**/*_spec.rb']
5
- end
3
+ RSpec::Core::RakeTask.new(:spec)
6
4
 
7
- task default: :test
5
+ task default: :spec
@@ -1,7 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gemspec
4
+
3
5
  gem 'mongoid', github: 'mongoid/mongoid'
4
- gem 'activesupport', '4.0.0.rc1'
5
6
 
6
7
  gem 'rspec'
7
8
  gem 'rake'
@@ -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
@@ -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 remove(options = {})
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
- alias :delete :remove
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
  #
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Paranoia
3
- VERSION = '0.3.0'
3
+ VERSION = '1.0.0.beta1'
4
4
  end
5
5
  end
@@ -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', '>= 3.0'
17
- gem.add_dependency 'mongoid', '>= 3.1.4'
16
+ gem.add_dependency 'activesupport'
17
+ gem.add_dependency 'mongoid', '4.0.0.beta1'
18
18
  end
@@ -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
@@ -6,7 +6,7 @@ class Acolyte
6
6
  embeds_many :versions, as: :memorable
7
7
  belongs_to :church
8
8
 
9
- default_scope asc(:name)
9
+ default_scope ->{ asc(:name) }
10
10
  scope :active, ->{ where(status: "active") }
11
11
  scope :named, ->{ where(:name.exists => true) }
12
12
 
@@ -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
@@ -3,5 +3,5 @@ class Appointment
3
3
  field :active, type: Boolean, default: true
4
4
  field :timed, type: Boolean, default: true
5
5
  embedded_in :person
6
- default_scope where(active: true)
6
+ default_scope ->{ where(active: true) }
7
7
  end
@@ -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
@@ -1,7 +1,5 @@
1
1
  class Building
2
2
  include Mongoid::Document
3
- attr_accessible
4
- attr_accessible :building_address, :contractors, as: :admin
5
3
  embeds_one :building_address
6
4
  embeds_many :contractors
7
5
  end
@@ -1,7 +1,5 @@
1
1
  class BuildingAddress
2
2
  include Mongoid::Document
3
- attr_accessible
4
- attr_accessible :city, as: :admin
5
3
  embedded_in :building
6
4
  field :city, type: String
7
5
  end
@@ -1,7 +1,5 @@
1
1
  class Contractor
2
2
  include Mongoid::Document
3
- attr_accessible
4
- attr_accessible :name, as: :admin
5
3
  embedded_in :building
6
4
  field :name, type: String
7
5
  end
@@ -2,5 +2,5 @@ class Dog
2
2
  include Mongoid::Document
3
3
  field :name, type: String
4
4
  has_and_belongs_to_many :breeds
5
- default_scope asc(:name)
5
+ default_scope ->{ asc(:name) }
6
6
  end
@@ -3,6 +3,4 @@ class Drug
3
3
  field :name, type: String
4
4
  field :generic, type: Boolean
5
5
  belongs_to :person, counter_cache: true
6
- attr_accessible :name, as: [ :default, :admin ]
7
- attr_accessible :person_id
8
6
  end
@@ -17,6 +17,6 @@ class Event
17
17
  end
18
18
  end
19
19
 
20
- scope :best, where(:kind.in => [ "party", "concert" ])
20
+ scope :best, ->{ where(:kind.in => [ "party", "concert" ]) }
21
21
  scope :by_kind, ->(kind){ where(:kind.in => [kind]) }
22
22
  end
@@ -13,8 +13,6 @@ class Game
13
13
 
14
14
  validates_format_of :name, without: /\$\$\$/
15
15
 
16
- attr_protected :_id
17
-
18
16
  set_callback(:initialize, :after) do |document|
19
17
  write_attribute("name", "Testing") unless name
20
18
  end
@@ -2,7 +2,6 @@ class House
2
2
  include Mongoid::Document
3
3
  field :name, type: String
4
4
  field :model, type: String
5
- attr_accessible :name, as: [ :default, :admin ]
6
5
 
7
- default_scope asc(:name)
6
+ default_scope ->{ asc(:name) }
8
7
  end
@@ -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"
@@ -15,8 +15,6 @@ class Name
15
15
 
16
16
  accepts_nested_attributes_for :language
17
17
 
18
- attr_protected :_id, :id
19
-
20
18
  def set_parent=(set = false)
21
19
  self.parent_title = namable.title if set
22
20
  end
@@ -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
@@ -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: Moped::BSON::ObjectId
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)
@@ -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) }
@@ -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
@@ -4,7 +4,4 @@ class Quiz
4
4
  field :name, type: String
5
5
  field :topic, type: String
6
6
  embeds_many :pages
7
-
8
- attr_accessible :topic, as: [ :default, :admin ]
9
- attr_accessible :name, as: :default
10
7
  end
@@ -1,4 +1,4 @@
1
1
  class Registry
2
2
  include Mongoid::Document
3
- field :data, type: Moped::BSON::Binary
3
+ field :data, type: BSON::Binary
4
4
  end
@@ -2,5 +2,5 @@ class Symptom
2
2
  include Mongoid::Document
3
3
  field :name, type: String
4
4
  embedded_in :person
5
- default_scope asc(:name)
5
+ default_scope ->{ asc(:name) }
6
6
  end
@@ -5,5 +5,5 @@ class Tree
5
5
  field :evergreen, type: Boolean
6
6
 
7
7
  scope :verdant, where(evergreen: true)
8
- default_scope asc(:name)
8
+ default_scope ->{ asc(:name) }
9
9
  end
@@ -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
@@ -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
- Mongoid::Threaded.persistence_options(ParanoidPost).should be_nil
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(:deleted_at, time)
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, consistency: :strong)
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 and clear the identity map before each spec.
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
- prerelease:
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: 2013-05-28 00:00:00.000000000 Z
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: '3.0'
29
- none: false
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: 3.1.4
37
- none: false
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: 3.1.4
45
- none: false
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: '0'
266
- none: false
267
+ version: 1.3.1
267
268
  requirements: []
268
269
  rubyforge_project:
269
- rubygems_version: 1.8.25
270
+ rubygems_version: 2.2.0
270
271
  signing_key:
271
- specification_version: 3
272
+ specification_version: 4
272
273
  summary: Extraction of mongoid-paranoia into its own gem.
273
274
  test_files: []
275
+ has_rdoc: