Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mongoid paranoia support #273

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Rubocop

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
env:
CI: true
TESTOPTS: '-v'
steps:
- uses: actions/checkout@v3
- name: Set up Ruby 3.2
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2
bundler-cache: true
- name: Run Rubocop
run: bundle exec rubocop --parallel
14 changes: 5 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ jobs:
experimental: [false]
include:
- ruby: 3.2
mongoid: HEAD
mongoid: head
experimental: true
- ruby: head
mongoid: 7
experimental: true
- ruby: head
mongoid: HEAD
mongoid: head
experimental: true
- ruby: jruby
mongoid: 7
experimental: true
- ruby: jruby
mongoid: 8
Expand Down Expand Up @@ -58,13 +61,6 @@ jobs:
env:
MONGOID_VERSION: ${{ matrix.mongoid }}

- name: rubocop
timeout-minutes: 5
run: bundle exec rubocop
continue-on-error: ${{ matrix.experimental }}
env:
MONGOID_VERSION: ${{ matrix.mongoid }}

- name: test
timeout-minutes: 10
run: bundle exec rake spec
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
## 7.0.1 (Next)
## 7.1.1 (Next)

* Your contribution here.

## 7.1.0 (2023/09/18)

* [#273](https://github.com/mongoid/mongoid-slug/pull/273): Add optional Mongoid::Paranoia support - [@johnnyshields](https://github.com/johnnyshields)

## 7.0.0 (2023/09/18)

* [#270](https://github.com/mongoid/mongoid-slug/pull/270): Drop support for Mongoid prior to version 7.0 - [@johnnyshields](https://github.com/johnnyshields)
Expand Down
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ source 'https://rubygems.org'
gemspec name: 'mongoid-slug'

case (version = ENV['MONGOID_VERSION'] || '8')
when 'HEAD'
when /\Ahead\z/i
gem 'mongoid', github: 'mongodb/mongoid'
when /\A\d+\z/
gem 'mongoid', "~> #{version}.0"
else
gem 'mongoid', version
end

gem 'mongoid_paranoia', '>= 0.6'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want to make a separate integration test that uses a different Gemfile for mongoid_paranoia to make sure it works without.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok good point. same thought crossed my mind.

gem 'rake'
gem 'rspec'
gem 'rspec-its'
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,19 @@ unique = Mongoid::Slug::UniqueSlug.new(Book.new).find_unique(title)
# return some representation of unique
```

### Compatibility with Mongoid::Paranoia

The [Mongoid::Paranoia](https://github.com/simi/mongoid_paranoia) gem provides soft-delete
functionality. If you are using this gem, please enable the global `use_paranoia` option.
This will automatically ensure that slugs will be cleared when soft-deleting a document,
and re-set when restoring a document.

```ruby
Mongoid::Slug.configure do |c|
c.use_paranoia = true
end
```

Contributing
------------

Expand Down
29 changes: 27 additions & 2 deletions lib/mongoid/slug.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ module Slug
end

class << self
attr_accessor :default_slug
attr_accessor :default_slug,
:use_paranoia

def configure(&block)
instance_eval(&block)
Expand Down Expand Up @@ -103,6 +104,16 @@ def slug(*fields, &block)
else
set_callback :save, :before, :build_slug, if: :slug_should_be_rebuilt?
end

# If paranoid document:
# - unset slugs on soft-destroy
# - recreate the slug on restore
# - force reset the slug when saving a destroyed paranoid document, to ensure it stays unset in the database
if __slug_paranoid_doc? # rubocop:disable Style/GuardClause
set_callback :destroy, :after, :unset_slug!
set_callback :restore, :before, :set_slug!
set_callback :save, :before, :clear_slug!, if: :slug_paranoid_deleted?
end
end

def default_slug_url_builder
Expand Down Expand Up @@ -147,6 +158,16 @@ def queryable
current_scope || Criteria.new(self) # Use Mongoid::Slug::Criteria for slugged documents.
end

# Returns whether to use paranoid functionality for this document.
#
# @return [ true | false ] Whether to use paranoid functionality
# for this document.
#
# @api private
def __slug_paranoid_doc?
!!(Mongoid::Slug.use_paranoia && defined?(::Mongoid::Paranoia) && self < ::Mongoid::Paranoia)
end

private

if Threaded.method(:current_scope).arity == -1
Expand Down Expand Up @@ -237,7 +258,11 @@ def find_unique_slug

# @return [Boolean] Whether the slug requires to be rebuilt
def slug_should_be_rebuilt?
new_record? || _slugs_changed? || slugged_attributes_changed?
(new_record? || _slugs_changed? || slugged_attributes_changed?) && !slug_paranoid_deleted?
end

def slug_paranoid_deleted?
!!(self.class.__slug_paranoid_doc? && !deleted_at.nil?)
end

def slugged_attributes_changed?
Expand Down
10 changes: 10 additions & 0 deletions spec/models/agent.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

class Agent
include Mongoid::Document
include Mongoid::Slug
include Mongoid::Paranoia

field :name
slug :name, permanent: true
end
12 changes: 12 additions & 0 deletions spec/models/secret_agent.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

Mongoid::Slug.use_paranoia = true
class SecretAgent
include Mongoid::Document
include Mongoid::Slug
include Mongoid::Paranoia

field :name
slug :name, permanent: true
end
Mongoid::Slug.use_paranoia = false
46 changes: 46 additions & 0 deletions spec/mongoid/paranoia_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

require 'spec_helper'

describe Mongoid::Slug do
context 'when paranoia support is not enabled' do
let!(:doc) { Agent.create(name: 'Garbo') }

it 'does not delete the slug when the document is destroyed' do
expect(doc.slug).to eq 'garbo'
doc.destroy
expect(Agent.unscoped.find(doc._id).slug).to eq 'garbo'
end
end

context 'when paranoia support is enabled' do
let!(:doc) { SecretAgent.create(name: 'Alaric') }

around do |example|
Mongoid::Slug.use_paranoia = true
example.run
ensure
Mongoid::Slug.use_paranoia = false
end

it 'deletes the slug when the document is destroyed' do
expect(doc.slug).to eq 'alaric'
doc.destroy
# TODO: This case should be nil.
expect(SecretAgent.unscoped.find(doc._id).slug).to eq doc._id.to_s
doc.restore
expect(SecretAgent.unscoped.find(doc._id).slug).to eq 'alaric'
end

it 'deletes the slug when deleted document is saved' do
expect(doc.slug).to eq 'alaric'
doc.deleted_at = Time.current
doc.save!
expect(SecretAgent.unscoped.find(doc._id).slug).to eq nil
# TODO: This case should re-set the slug.
doc.deleted_at = nil
doc.save!
expect(SecretAgent.unscoped.find(doc._id).slug).to eq nil
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require 'active_support'
require 'active_support/deprecation'
require 'mongoid'
require 'mongoid/paranoia'

require File.expand_path '../lib/mongoid/slug', __dir__

Expand Down
Loading