From 4c47adf2918dbeb4bb3815c2f1d94f048f342efe Mon Sep 17 00:00:00 2001 From: Johnny Shields Date: Thu, 12 Aug 2021 02:47:42 +0900 Subject: [PATCH 1/6] Fix typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1041701..88f5738 100644 --- a/README.md +++ b/README.md @@ -295,7 +295,7 @@ For example, if `I18n.default_locale` is `:en`, the index will be generated as f ```ruby slug :title, localize: true -# The following indexes is auto-generated: +# The following index is auto-generated: index({ '_slugs.en' => 1 }, { unique: true, sparse: true }) ``` From 58917341eec480be55015ed5651cd6987e509c25 Mon Sep 17 00:00:00 2001 From: Johnny Shields Date: Fri, 13 Aug 2021 02:11:40 +0900 Subject: [PATCH 2/6] Drop support for Mongoid 6 and Ruby 2.4 (#270) * Drop support for: - Mongoid 6 and earlier - Ruby 2.4 and earlier * - Update Rubocop and auto-fix some cops - Remove gem Guard - Remove gem AwesomePrint - Remove gem mongoid-compatibility - Set version to 7.0.0 --- .github/workflows/test.yml | 20 +--- .rubocop.yml | 17 ++- .rubocop_todo.yml | 68 ++++-------- CHANGELOG.md | 3 +- Dangerfile | 2 + Gemfile | 13 +-- Guardfile | 6 - README.md | 17 ++- Rakefile | 2 + UPGRADING.md | 6 + lib/mongoid/slug.rb | 21 ++-- lib/mongoid/slug/criteria.rb | 16 ++- lib/mongoid/slug/index_builder.rb | 2 + lib/mongoid/slug/railtie.rb | 2 + lib/mongoid/slug/slug_id_strategy.rb | 2 + lib/mongoid/slug/unique_slug.rb | 15 +-- lib/mongoid/slug/version.rb | 4 +- lib/mongoid_slug.rb | 2 + lib/tasks/mongoid_slug.rake | 2 + mongoid-slug.gemspec | 9 +- spec/models/alias.rb | 2 + spec/models/article.rb | 2 + spec/models/artist.rb | 2 + spec/models/artwork.rb | 2 + spec/models/author.rb | 8 +- spec/models/author_polymorphic.rb | 8 +- spec/models/book.rb | 2 + spec/models/book_polymorphic.rb | 2 + spec/models/caption.rb | 2 + spec/models/entity.rb | 2 + spec/models/friend.rb | 2 + spec/models/incorrect_slug_persistence.rb | 2 + spec/models/integer_id.rb | 2 + spec/models/magazine.rb | 2 + spec/models/page.rb | 2 + spec/models/page_localize.rb | 2 + spec/models/page_slug_localized.rb | 2 + spec/models/page_slug_localized_custom.rb | 2 + spec/models/page_slug_localized_history.rb | 2 + spec/models/partner.rb | 2 + spec/models/person.rb | 8 +- spec/models/relationship.rb | 2 + spec/models/string_id.rb | 2 + spec/models/subject.rb | 2 + spec/models/without_slug.rb | 2 + spec/mongoid/criteria_spec.rb | 2 + spec/mongoid/index_builder_spec.rb | 32 +++--- spec/mongoid/slug_spec.rb | 121 +++++++++------------ spec/shared/indexes.rb | 14 +-- spec/spec_helper.rb | 17 +-- spec/tasks/mongoid_slug_rake_spec.rb | 2 + 51 files changed, 250 insertions(+), 235 deletions(-) delete mode 100644 Guardfile diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 83c6397..a97250e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,28 +13,10 @@ jobs: continue-on-error: ${{ matrix.experimental }} strategy: matrix: - ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, jruby, truffleruby] + ruby: [2.5, 2.6, 2.7, 3.0, jruby, truffleruby] mongoid: [7] experimental: [false] include: - - ruby: 2.1 - mongoid: 3 - experimental: false - - ruby: 2.2 - mongoid: 3 - experimental: false - - ruby: 2.3 - mongoid: 3 - experimental: false - # - ruby: 2.3 - # mongoid: 4 - # experimental: false - - ruby: 2.3 - mongoid: 5 - experimental: false - - ruby: 2.3 - mongoid: 6 - experimental: false - ruby: 2.7 mongoid: HEAD experimental: true diff --git a/.rubocop.yml b/.rubocop.yml index fbd6c1b..8da7c7d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,11 +1,22 @@ +inherit_from: .rubocop_todo.yml + AllCops: - Exclude: - - vendor/**/* + TargetRubyVersion: 2.5 + NewCops: enable + SuggestExtensions: false Style/Documentation: Enabled: false +Style/DoubleNegation: + Enabled: false + Style/ModuleFunction: EnforcedStyle: extend_self -inherit_from: .rubocop_todo.yml +Style/OptionalBooleanParameter: + Enabled: false + +Style/Semicolon: + Exclude: + - 'spec/**/*.rb' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 5ffa069..dd08ae7 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,73 +1,53 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2018-08-16 08:14:07 -0400 using RuboCop version 0.58.2. +# on 2021-08-11 17:20:10 UTC using RuboCop version 1.18.4. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 6 -# Configuration parameters: Include. -# Include: **/*.gemfile, **/Gemfile, **/gems.rb -Bundler/DuplicatedGem: +# Offense count: 5 +# Configuration parameters: AllowedMethods. +# AllowedMethods: enums +Lint/ConstantDefinitionInBlock: Exclude: - - 'Gemfile' + - 'spec/mongoid/slug_spec.rb' + - 'spec/tasks/mongoid_slug_rake_spec.rb' -# Offense count: 5 +# Offense count: 4 +# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. Metrics/AbcSize: - Max: 40 + Max: 44 -# Offense count: 23 -# Configuration parameters: CountComments, ExcludedMethods. -# ExcludedMethods: refine +# Offense count: 24 +# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. +# IgnoredMethods: refine Metrics/BlockLength: - Max: 532 + Max: 525 # Offense count: 2 +# Configuration parameters: IgnoredMethods. Metrics/CyclomaticComplexity: - Max: 9 + Max: 10 -# Offense count: 6 -# Configuration parameters: CountComments. +# Offense count: 7 +# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. Metrics/MethodLength: Max: 23 # Offense count: 2 -# Configuration parameters: CountComments. +# Configuration parameters: CountComments, CountAsOne. Metrics/ModuleLength: - Max: 959 + Max: 937 -# Offense count: 2 +# Offense count: 1 +# Configuration parameters: IgnoredMethods. Metrics/PerceivedComplexity: - Max: 10 + Max: 11 # Offense count: 1 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: braces, no_braces, context_dependent -Style/BracesAroundHashParameters: - Exclude: - - 'lib/mongoid/slug/criteria.rb' - -# Offense count: 1 +# Configuration parameters: AllowOnConstant. Style/CaseEquality: Exclude: - 'lib/mongoid/slug/unique_slug.rb' - -# Offense count: 1 -Style/DoubleNegation: - Exclude: - - 'lib/mongoid/slug.rb' - -# Offense count: 9 -# Cop supports --auto-correct. -# Configuration parameters: AllowAsExpressionSeparator. -Style/Semicolon: - Exclude: - - 'spec/mongoid/criteria_spec.rb' - -# Offense count: 151 -# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. -# URISchemes: http, https -Metrics/LineLength: - Max: 138 diff --git a/CHANGELOG.md b/CHANGELOG.md index e8fac2a..eba03ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ -## 6.0.2 (Next) +## 7.0.0 (Next) * Your contribution here. +* [#268](https://github.com/mongoid/mongoid-slug/pull/268): Ensure localized slugs index expected localized slug fields - [@johnnyshields](https://github.com/johnnyshields). ## 6.0.1 (2021/08/12) diff --git a/Dangerfile b/Dangerfile index 6248c90..de2a4a0 100644 --- a/Dangerfile +++ b/Dangerfile @@ -1 +1,3 @@ +# frozen_string_literal: true + danger.import_dangerfile(gem: 'mongoid-danger') diff --git a/Gemfile b/Gemfile index 82bb5ed..d6f3782 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://rubygems.org' gemspec name: 'mongoid-slug' @@ -7,19 +9,12 @@ when 'HEAD' gem 'mongoid', github: 'mongodb/mongoid' when /^7/ gem 'mongoid', '~> 7' -when /^6/ - gem 'mongoid', '~> 6' -when /^5/ - gem 'mongoid', '~> 5' -when /^4/ - gem 'mongoid', '~> 4' -when /^3/ - gem 'mongoid', '~> 3' else gem 'mongoid', version end group :test do gem 'mongoid-danger', '~> 0.1.0', require: false - gem 'rubocop', '0.57.2' + gem 'rubocop', '~> 1.18.4' + gem 'rubocop-rspec' end diff --git a/Guardfile b/Guardfile deleted file mode 100644 index 4d4e707..0000000 --- a/Guardfile +++ /dev/null @@ -1,6 +0,0 @@ -guard 'rspec', cli: '-fd' do - notification :off - watch(%r{^spec/.+_spec\.rb$}) - watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } - watch('spec/spec_helper.rb') { 'spec' } -end diff --git a/README.md b/README.md index 88f5738..36e8bdf 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,12 @@ It sits idly on top of [stringex](https://github.com/rsl/stringex), supporting n [![Gem Version](https://badge.fury.io/rb/mongoid-slug.svg)](http://badge.fury.io/rb/mongoid-slug) [![Code Climate](https://codeclimate.com/github/mongoid/mongoid-slug.svg)](https://codeclimate.com/github/mongoid/mongoid-slug) +### Version Support + +Mongoid Slug 7.x requires at least Mongoid 7.0.0 and Ruby 2.5.0. For earlier Mongoid and Ruby version support, please use an earlier version of Mongoid Slug. + +Mongoid Slug is compatible with all MongoDB versions which Mongoid supports, however, please see "Slug Max Length" section below for MongoDB 4.0 and earlier. + ### Installation Add to your Gemfile: @@ -169,9 +175,16 @@ class Employee end ``` -### Limit Slug Length +### Slug Max Length -MongoDB has a default limit around 1KB to the size of the index keys and will raise error 17280, `key too large to index` when trying to create a record that causes an index key to exceed that limit. By default slugs are of the form `text[-number]` and the text portion is limited in size to `Mongoid::Slug::MONGO_INDEX_KEY_LIMIT_BYTES - 32` bytes. You can change this limit with `max_length` or set it to `nil` if you're running MongoDB with [failIndexKeyTooLong](https://docs.mongodb.org/manual/reference/parameters/#param.failIndexKeyTooLong) set to `false`. +MongoDB [featureCompatibilityVersion](https://docs.mongodb.com/manual/reference/command/setFeatureCompatibilityVersion/#std-label-view-fcv) +"4.0" and earlier applies an [Index Key Limit](https://docs.mongodb.com/manual/reference/limits/#mongodb-limit-Index-Key-Limit) +which limits the total size of an index entry to around 1KB and will raise error, +`17280 - key too large to index` when trying to create a record that causes an index key to exceed that limit. +By default slugs are of the form `text[-number]` and the text portion is limited in size +to `Mongoid::Slug::MONGO_INDEX_KEY_LIMIT_BYTES - 32` bytes. +You can change this limit with `max_length` or set it to `nil` if you're running MongoDB +with [failIndexKeyTooLong](https://docs.mongodb.org/manual/reference/parameters/#param.failIndexKeyTooLong) set to `false`. ```ruby class Company diff --git a/Rakefile b/Rakefile index 25865f3..735d538 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'bundler' require 'rspec/core/rake_task' diff --git a/UPGRADING.md b/UPGRADING.md index ccb5bdc..3c6deb8 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,3 +1,9 @@ +### Upgrading to 7.0.0 + +#### Support dropped for Mongoid < 7 and Ruby < 2.5 + +Please upgrade to at least Mongoid 7.0 and Ruby 2.5. + ### Upgrading to 6.0.0 #### Support dropped for mongoid_paranoia diff --git a/lib/mongoid/slug.rb b/lib/mongoid/slug.rb index d17df84..1be4199 100644 --- a/lib/mongoid/slug.rb +++ b/lib/mongoid/slug.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + require 'mongoid' require 'stringex' require 'mongoid/slug/criteria' require 'mongoid/slug/index_builder' require 'mongoid/slug/unique_slug' require 'mongoid/slug/slug_id_strategy' -require 'mongoid-compatibility' require 'mongoid/slug/railtie' if defined?(Rails) module Mongoid @@ -29,6 +30,7 @@ module Slug class << self attr_accessor :default_slug + def configure(&block) instance_eval(&block) end @@ -85,7 +87,10 @@ def slug(*fields, &block) alias_attribute :slugs, :_slugs # Set indexes - Mongoid::Slug::IndexBuilder.build_indexes(self, slug_scope_key, slug_by_model_type, options[:localize]) unless embedded? + unless embedded? + Mongoid::Slug::IndexBuilder.build_indexes(self, slug_scope_key, slug_by_model_type, + options[:localize]) + end self.slug_url_builder = block_given? ? block : default_slug_url_builder @@ -111,6 +116,7 @@ def look_like_slugs?(*args) # @return [ Array, Document ] def slug_scope_key return nil unless slug_scope + reflect_on_association(slug_scope).try(:key) || slug_scope end @@ -141,17 +147,13 @@ def queryable private - if Mongoid::Compatibility::Version.mongoid5_or_newer? && Threaded.method(:current_scope).arity == -1 + if Threaded.method(:current_scope).arity == -1 def current_scope Threaded.current_scope(self) end - elsif Mongoid::Compatibility::Version.mongoid5_or_newer? - def current_scope - Threaded.current_scope - end else def current_scope - scope_stack.last + Threaded.current_scope end end end @@ -184,7 +186,7 @@ def apply_slug return true if new_slug.size.zero? # avoid duplicate slugs - _slugs.delete(new_slug) if _slugs + _slugs&.delete(new_slug) if !!slug_history && _slugs.is_a?(Array) append_slug(new_slug) @@ -249,6 +251,7 @@ def to_param # @return [String] the slug, or nil if the document does not have a slug. def slug return _slugs.last if _slugs + _id.to_s end diff --git a/lib/mongoid/slug/criteria.rb b/lib/mongoid/slug/criteria.rb index 85d7d6f..09b7de4 100644 --- a/lib/mongoid/slug/criteria.rb +++ b/lib/mongoid/slug/criteria.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Mongoid module Slug class Criteria < Mongoid::Criteria @@ -50,6 +52,7 @@ def find_by_slug!(*args) def look_like_slugs?(args) return false unless args.all? { |id| id.is_a?(String) } + id_field = @klass.fields['_id'] @slug_strategy ||= id_field.options[:slug_id_strategy] || build_slug_strategy(id_field.type) args.none? { |id| @slug_strategy.call(id) } @@ -61,13 +64,13 @@ def look_like_slugs?(args) # use object_id or string strategy depending on the id_type # otherwise default for all other id_types def build_slug_strategy(id_type) - type_method = id_type.to_s.downcase.split('::').last + '_slug_strategy' + type_method = "#{id_type.to_s.downcase.split('::').last}_slug_strategy" respond_to?(type_method, true) ? method(type_method) : ->(_id) { false } end # a string will not look like a slug if it looks like a legal BSON::ObjectId def objectid_slug_strategy(id) - Mongoid::Compatibility::ObjectId.legal?(id) + BSON::ObjectId.legal?(id) end # a string will always look like a slug @@ -78,10 +81,10 @@ def string_slug_strategy(_id) def for_slugs(slugs) # _translations localized = (begin - @klass.fields['_slugs'].options[:localize] - rescue StandardError - false - end) + @klass.fields['_slugs'].options[:localize] + rescue StandardError + false + end) if localized def_loc = I18n.default_locale query = { '$in' => slugs } @@ -100,6 +103,7 @@ def execute_or_raise_for_slugs(slugs, multi) def check_for_missing_documents_for_slugs!(result, slugs) missing_slugs = slugs - result.map(&:slugs).flatten return unless !missing_slugs.blank? && Mongoid.raise_not_found_error + raise Errors::DocumentNotFound.new(klass, slugs, missing_slugs) end end diff --git a/lib/mongoid/slug/index_builder.rb b/lib/mongoid/slug/index_builder.rb index 82bc24d..8158f8d 100644 --- a/lib/mongoid/slug/index_builder.rb +++ b/lib/mongoid/slug/index_builder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Mongoid module Slug module IndexBuilder diff --git a/lib/mongoid/slug/railtie.rb b/lib/mongoid/slug/railtie.rb index c734d71..a77f0f5 100644 --- a/lib/mongoid/slug/railtie.rb +++ b/lib/mongoid/slug/railtie.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Mongoid module Slug class Railtie < Rails::Railtie diff --git a/lib/mongoid/slug/slug_id_strategy.rb b/lib/mongoid/slug/slug_id_strategy.rb index b244251..c1a78d7 100644 --- a/lib/mongoid/slug/slug_id_strategy.rb +++ b/lib/mongoid/slug/slug_id_strategy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Mongoid::Fields.option(:slug_id_strategy) do |_model, field, value| field.options[:slug_id_strategy] = value end diff --git a/lib/mongoid/slug/unique_slug.rb b/lib/mongoid/slug/unique_slug.rb index 9067147..471b4bd 100644 --- a/lib/mongoid/slug/unique_slug.rb +++ b/lib/mongoid/slug/unique_slug.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'forwardable' # Can use e.g. Mongoid::Slug::UniqueSlug.new(ModelClass.new).find_unique "slug-1" for auto-suggest ui @@ -20,9 +22,12 @@ def initialize(slug, documents, pattern) @documents.each do |doc| history_slugs = doc._slugs next if history_slugs.nil? + existing_slugs.push(*history_slugs.find_all { |cur_slug| cur_slug =~ regexp_pattern }) last_entered_slug.push(*history_slugs.last) if history_slugs.last =~ regexp_pattern - existing_history_slugs.push(*history_slugs.first(history_slugs.length - 1).find_all { |cur_slug| cur_slug =~ regexp_pattern }) + existing_history_slugs.push(*history_slugs.first(history_slugs.length - 1).find_all do |cur_slug| + cur_slug =~ regexp_pattern + end) end end @@ -132,7 +137,7 @@ def escaped_pattern # index to match /^.../ pattern. # Use Regexp::Raw to avoid the multiline option when querying the server. def regex_for_slug - if embedded? || Mongoid::Compatibility::Version.mongoid3? || Mongoid::Compatibility::Version.mongoid4? + if embedded? Regexp.new(escaped_pattern) else BSON::Regexp::Raw.new(escaped_pattern) @@ -155,11 +160,7 @@ def uniqueness_scope end if embedded? - parent_metadata = if Mongoid::Compatibility::Version.mongoid7_or_newer? - reflect_on_all_association(:embedded_in)[0] - else - reflect_on_all_associations(:embedded_in)[0] - end + parent_metadata = reflect_on_all_association(:embedded_in)[0] return model._parent.send(parent_metadata.inverse_of || self.metadata.name) end diff --git a/lib/mongoid/slug/version.rb b/lib/mongoid/slug/version.rb index e36f63c..1d4f848 100644 --- a/lib/mongoid/slug/version.rb +++ b/lib/mongoid/slug/version.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + module Mongoid #:nodoc: module Slug - VERSION = '6.0.1'.freeze + VERSION = '7.0.0' end end diff --git a/lib/mongoid_slug.rb b/lib/mongoid_slug.rb index d444d9e..399e7c7 100644 --- a/lib/mongoid_slug.rb +++ b/lib/mongoid_slug.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + # To be removed require 'mongoid/slug' diff --git a/lib/tasks/mongoid_slug.rake b/lib/tasks/mongoid_slug.rake index 1b9fb64..dea5148 100644 --- a/lib/tasks/mongoid_slug.rake +++ b/lib/tasks/mongoid_slug.rake @@ -1,3 +1,5 @@ +# frozen_string_literal: true + namespace :mongoid_slug do desc 'Goes though all documents and sets slug if not already set' task set: :environment do |_, args| diff --git a/mongoid-slug.gemspec b/mongoid-slug.gemspec index 4edb9b2..34fb83e 100644 --- a/mongoid-slug.gemspec +++ b/mongoid-slug.gemspec @@ -1,3 +1,5 @@ +# frozen_string_literal: true + $LOAD_PATH.push File.expand_path('lib', __dir__) require 'mongoid/slug/version' @@ -12,13 +14,10 @@ Gem::Specification.new do |s| s.description = 'Mongoid URL slug or permalink generator' s.license = 'MIT' - s.rubyforge_project = 'mongoid-slug' + s.required_ruby_version = '>= 2.5' - s.add_dependency 'mongoid', '>= 3.0' - s.add_dependency 'mongoid-compatibility' + s.add_dependency 'mongoid', '>= 7.0' s.add_dependency 'stringex', '~> 2.0' - s.add_development_dependency 'awesome_print' - s.add_development_dependency 'guard-rspec' s.add_development_dependency 'rake' s.add_development_dependency 'rspec' s.add_development_dependency 'rspec-its' diff --git a/spec/models/alias.rb b/spec/models/alias.rb index f0ada23..f149804 100644 --- a/spec/models/alias.rb +++ b/spec/models/alias.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Alias include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/article.rb b/spec/models/article.rb index ed45285..6a6b57c 100644 --- a/spec/models/article.rb +++ b/spec/models/article.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Article include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/artist.rb b/spec/models/artist.rb index cbbb279..e44441f 100644 --- a/spec/models/artist.rb +++ b/spec/models/artist.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Artist include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/artwork.rb b/spec/models/artwork.rb index bf261cd..294fa16 100644 --- a/spec/models/artwork.rb +++ b/spec/models/artwork.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Artwork include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/author.rb b/spec/models/author.rb index d634198..f06d538 100644 --- a/spec/models/author.rb +++ b/spec/models/author.rb @@ -1,13 +1,11 @@ +# frozen_string_literal: true + class Author include Mongoid::Document include Mongoid::Slug field :first_name field :last_name - if Mongoid::Compatibility::Version.mongoid6_or_newer? - belongs_to :book, required: false - else - belongs_to :book - end + belongs_to :book, required: false has_many :characters, class_name: 'Person', foreign_key: :author_id diff --git a/spec/models/author_polymorphic.rb b/spec/models/author_polymorphic.rb index 3ecd337..31f6a82 100644 --- a/spec/models/author_polymorphic.rb +++ b/spec/models/author_polymorphic.rb @@ -1,14 +1,12 @@ +# frozen_string_literal: true + class AuthorPolymorphic include Mongoid::Document include Mongoid::Slug field :first_name field :last_name slug :first_name, :last_name, scope: :book_polymorphic - if Mongoid::Compatibility::Version.mongoid6_or_newer? - belongs_to :book_polymorphic, required: false - else - belongs_to :book_polymorphic - end + belongs_to :book_polymorphic, required: false has_many :characters, class_name: 'Person', foreign_key: :author_id diff --git a/spec/models/book.rb b/spec/models/book.rb index dedae8d..173d8c2 100644 --- a/spec/models/book.rb +++ b/spec/models/book.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Book include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/book_polymorphic.rb b/spec/models/book_polymorphic.rb index 010ec88..a56967a 100644 --- a/spec/models/book_polymorphic.rb +++ b/spec/models/book_polymorphic.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BookPolymorphic include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/caption.rb b/spec/models/caption.rb index cb6d514..11fb3a2 100644 --- a/spec/models/caption.rb +++ b/spec/models/caption.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Caption include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/entity.rb b/spec/models/entity.rb index 2f5d42d..410f5e9 100644 --- a/spec/models/entity.rb +++ b/spec/models/entity.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Entity include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/friend.rb b/spec/models/friend.rb index 5cda316..54ec404 100644 --- a/spec/models/friend.rb +++ b/spec/models/friend.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Friend include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/incorrect_slug_persistence.rb b/spec/models/incorrect_slug_persistence.rb index 20cd5d2..b9c180e 100644 --- a/spec/models/incorrect_slug_persistence.rb +++ b/spec/models/incorrect_slug_persistence.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class IncorrectSlugPersistence include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/integer_id.rb b/spec/models/integer_id.rb index a2ff287..25a7084 100644 --- a/spec/models/integer_id.rb +++ b/spec/models/integer_id.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class IntegerId include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/magazine.rb b/spec/models/magazine.rb index 3a1695e..ec0b626 100644 --- a/spec/models/magazine.rb +++ b/spec/models/magazine.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Magazine include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/page.rb b/spec/models/page.rb index e533898..aff4612 100644 --- a/spec/models/page.rb +++ b/spec/models/page.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Page include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/page_localize.rb b/spec/models/page_localize.rb index 0eaa952..6087d68 100644 --- a/spec/models/page_localize.rb +++ b/spec/models/page_localize.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PageLocalize include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/page_slug_localized.rb b/spec/models/page_slug_localized.rb index 0a9dba8..7e9751c 100644 --- a/spec/models/page_slug_localized.rb +++ b/spec/models/page_slug_localized.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PageSlugLocalized include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/page_slug_localized_custom.rb b/spec/models/page_slug_localized_custom.rb index 48e44b8..c0cea2e 100644 --- a/spec/models/page_slug_localized_custom.rb +++ b/spec/models/page_slug_localized_custom.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PageSlugLocalizedCustom include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/page_slug_localized_history.rb b/spec/models/page_slug_localized_history.rb index e86e847..d590214 100644 --- a/spec/models/page_slug_localized_history.rb +++ b/spec/models/page_slug_localized_history.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PageSlugLocalizedHistory include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/partner.rb b/spec/models/partner.rb index 8a03d83..7caa941 100644 --- a/spec/models/partner.rb +++ b/spec/models/partner.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Partner include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/person.rb b/spec/models/person.rb index 5447954..02ec647 100644 --- a/spec/models/person.rb +++ b/spec/models/person.rb @@ -1,12 +1,10 @@ +# frozen_string_literal: true + class Person include Mongoid::Document include Mongoid::Slug field :name slug :name, permanent: true, scope: :author embeds_many :relationships - if Mongoid::Compatibility::Version.mongoid6_or_newer? - belongs_to :author, inverse_of: :characters, required: false - else - belongs_to :author, inverse_of: :characters - end + belongs_to :author, inverse_of: :characters, required: false end diff --git a/spec/models/relationship.rb b/spec/models/relationship.rb index 70fb11f..44e289c 100644 --- a/spec/models/relationship.rb +++ b/spec/models/relationship.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Relationship include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/string_id.rb b/spec/models/string_id.rb index 89d2109..dd39c59 100644 --- a/spec/models/string_id.rb +++ b/spec/models/string_id.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StringId include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/subject.rb b/spec/models/subject.rb index e3150cf..db45b10 100644 --- a/spec/models/subject.rb +++ b/spec/models/subject.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Subject include Mongoid::Document include Mongoid::Slug diff --git a/spec/models/without_slug.rb b/spec/models/without_slug.rb index 89cc244..4b8779c 100644 --- a/spec/models/without_slug.rb +++ b/spec/models/without_slug.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class WithoutSlug include Mongoid::Document diff --git a/spec/mongoid/criteria_spec.rb b/spec/mongoid/criteria_spec.rb index 240eea9..f2505ca 100644 --- a/spec/mongoid/criteria_spec.rb +++ b/spec/mongoid/criteria_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Mongoid::Slug::Criteria do diff --git a/spec/mongoid/index_builder_spec.rb b/spec/mongoid/index_builder_spec.rb index f3cc26a..3ec3aef 100644 --- a/spec/mongoid/index_builder_spec.rb +++ b/spec/mongoid/index_builder_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Mongoid::Slug::IndexBuilder do @@ -7,13 +9,7 @@ let(:default_locale) { :en } let(:locales) { nil } - subject do - if Mongoid::Compatibility::Version.mongoid3? - doc.index_options.to_a - else - doc.index_specifications.map { |spec| [spec.key, spec.options] } - end - end + subject { doc.index_specifications.map { |spec| [spec.key, spec.options] } } before do allow(I18n).to receive(:default_locale).and_return(default_locale) @@ -37,7 +33,7 @@ let(:default_locale) { :de } let(:locales) { true } - it { is_expected.to eq [[{ :'_slugs.de' => 1, foo: 1 }, {}]] } + it { is_expected.to eq [[{ '_slugs.de': 1, foo: 1 }, {}]] } end context 'when locale is not set' do @@ -48,9 +44,9 @@ let(:locales) { %i[es de fr] } it do - is_expected.to eq [[{ :'_slugs.es' => 1, foo: 1 }, {}], - [{ :'_slugs.de' => 1, foo: 1 }, {}], - [{ :'_slugs.fr' => 1, foo: 1 }, {}]] + is_expected.to eq [[{ '_slugs.es': 1, foo: 1 }, {}], + [{ '_slugs.de': 1, foo: 1 }, {}], + [{ '_slugs.fr': 1, foo: 1 }, {}]] end end end @@ -69,28 +65,28 @@ context 'when locales is true' do let(:locales) { true } - it { is_expected.to eq [[{ :'_slugs.en' => 1 }, { unique: true, sparse: true }]] } + it { is_expected.to eq [[{ '_slugs.en': 1 }, { unique: true, sparse: true }]] } end context 'when locales is a String' do let(:locales) { 'de' } - it { is_expected.to eq [[{ :'_slugs.de' => 1 }, { unique: true, sparse: true }]] } + it { is_expected.to eq [[{ '_slugs.de': 1 }, { unique: true, sparse: true }]] } end context 'when locales is a Symbol' do let(:locales) { :de } - it { is_expected.to eq [[{ :'_slugs.de' => 1 }, { unique: true, sparse: true }]] } + it { is_expected.to eq [[{ '_slugs.de': 1 }, { unique: true, sparse: true }]] } end context 'when locales is an Array' do let(:locales) { %i[es de fr] } it do - is_expected.to eq [[{ :'_slugs.es' => 1 }, { unique: true, sparse: true }], - [{ :'_slugs.de' => 1 }, { unique: true, sparse: true }], - [{ :'_slugs.fr' => 1 }, { unique: true, sparse: true }]] + is_expected.to eq [[{ '_slugs.es': 1 }, { unique: true, sparse: true }], + [{ '_slugs.de': 1 }, { unique: true, sparse: true }], + [{ '_slugs.fr': 1 }, { unique: true, sparse: true }]] end end @@ -99,7 +95,7 @@ let(:default_locale) { :fr } let(:by_model_type) { true } - it { is_expected.to eq [[{ :'_slugs.fr' => 1, _type: 1 }, {}]] } + it { is_expected.to eq [[{ '_slugs.fr': 1, _type: 1 }, {}]] } end end end diff --git a/spec/mongoid/slug_spec.rb b/spec/mongoid/slug_spec.rb index c4e401e..2fbcaa5 100644 --- a/spec/mongoid/slug_spec.rb +++ b/spec/mongoid/slug_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module Mongoid @@ -67,7 +69,8 @@ module Mongoid expect(entity0.to_param).to eql 'pelham-1-2-3' 5.times do |x| - dup = Entity.create(_id: UUID.generate, name: entity0.name, user_edited_variation: entity0.user_edited_variation) + dup = Entity.create(_id: UUID.generate, name: entity0.name, + user_edited_variation: entity0.user_edited_variation) expect(dup.to_param).to eql "pelham-1-2-3-#{x.succ}" end end @@ -121,7 +124,7 @@ module Mongoid end it 'does not allow a BSON::ObjectId as use for a slug' do - bson_id = Mongoid::Compatibility::Version.mongoid3? ? Moped::BSON::ObjectId.new.to_s : BSON::ObjectId.new.to_s + bson_id = BSON::ObjectId.new.to_s bad = Book.create(title: bson_id) expect(bad.slugs).not_to include(bson_id) end @@ -404,6 +407,7 @@ module Mongoid expect(book.slugs.find_all { |slug| slug == 'book-title' }.size).to eql 1 end end + context 'false' do let(:author) do Author.create(first_name: 'Gilles', last_name: 'Deleuze') @@ -594,29 +598,6 @@ class Person it_should_behave_like 'has an index', { _slugs: 1 }, unique: true, sparse: true end - context 'with a value exceeding mongodb max index key' do - if Mongoid::Compatibility::Version.mongoid5_or_newer? - xit 'errors with a model without a max length' do - expect do - Book.create!(title: 't' * 1025) - end.to raise_error Mongo::Error::OperationFailure, /key too large to index/ - end - elsif Mongoid::Compatibility::Version.mongoid4? - xit 'errors with a model without a max length' do - expect do - Book.create!(title: 't' * 1025) - end.to raise_error Moped::Errors::OperationFailure, /key too large to index/ - end - end - - it 'succeeds with a model with a max length' do - expect do - author = Author.create!(last_name: 't' * 1025) - expect(author.slug.length).to eq 256 - end.to_not raise_error - end - end - context 'when slug is scoped by a reference association' do subject { Author } it_should_behave_like 'does not have an index', _slugs: 1 @@ -686,6 +667,7 @@ class Person end end end + context 'when the model does not have any reserved words set' do %w[new edit].each do |word| it "does not use the default reserved word '#{word}'" do @@ -736,11 +718,7 @@ class Person context 'when called on an existing record with no slug' do let!(:book_no_slug) do - if Mongoid::Compatibility::Version.mongoid5_or_newer? - Book.collection.insert_one(title: 'Proust and Signs') - else - Book.collection.insert(title: 'Proust and Signs') - end + Book.collection.insert_one(title: 'Proust and Signs') Book.where(title: 'Proust and Signs').first end @@ -773,16 +751,16 @@ class Person end describe 'when regular expression matches, but document does not' do - let!(:book_1) { Book.create(title: 'book-1') } - let!(:book_2) { Book.create(title: 'book') } - let!(:book_3) { Book.create(title: 'book') } + let!(:book1) { Book.create(title: 'book-1') } + let!(:book2) { Book.create(title: 'book') } + let!(:book3) { Book.create(title: 'book') } - it 'book_2 should have the user supplied title without -1 after it' do - expect(book_2.to_param).to eql 'book' + it 'book2 should have the user supplied title without -1 after it' do + expect(book2.to_param).to eql 'book' end - it 'book_3 should have a generated slug' do - expect(book_3.to_param).to eql 'book-2' + it 'book3 should have a generated slug' do + expect(book3.to_param).to eql 'book-2' end end @@ -796,15 +774,9 @@ class Person it 'ensures uniqueness' do book1 = Book.create(title: 'A Thousand Plateaus', slugs: ['not-what-you-expected']) expect(book1.to_param).to eql 'not-what-you-expected' - if Mongoid::Compatibility::Version.mongoid5_or_newer? - expect do - Book.create(title: 'A Thousand Plateaus', slugs: ['not-what-you-expected']) - end.to raise_error Mongo::Error::OperationFailure, /duplicate/ - elsif Mongoid::Compatibility::Version.mongoid4? - expect do - Book.create(title: 'A Thousand Plateaus', slugs: ['not-what-you-expected']) - end.to raise_error Moped::Errors::OperationFailure, /duplicate/ - end + expect do + Book.create(title: 'A Thousand Plateaus', slugs: ['not-what-you-expected']) + end.to raise_error Mongo::Error::OperationFailure, /duplicate/ end it 'updates the slug when a new one is passed in' do @@ -825,15 +797,9 @@ class Person Book.create(title: 'Sleepyhead') book2 = Book.create(title: 'A Thousand Plateaus') book2.slugs.push 'sleepyhead' - if Mongoid::Compatibility::Version.mongoid5_or_newer? - expect do - book2.save - end.to raise_error Mongo::Error::OperationFailure, /duplicate/ - elsif Mongoid::Compatibility::Version.mongoid4? - expect do - book2.save - end.to raise_error Moped::Errors::OperationFailure, /duplicate/ - end + expect do + book2.save + end.to raise_error Mongo::Error::OperationFailure, /duplicate/ end end @@ -884,16 +850,16 @@ class Person # Turn on i18n fallback require 'i18n/backend/fallbacks' - I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) + I18n::Backend::Simple.include I18n::Backend::Fallbacks ::I18n.fallbacks[:nl] = %i[nl en] expect(page.slug).to eql 'title-on-english' fallback_slug = page.slug fallback_page = begin - PageSlugLocalized.find(fallback_slug) - rescue StandardError - nil - end + PageSlugLocalized.find(fallback_slug) + rescue StandardError + nil + end expect(fallback_page).to eq(page) # Restore fallback for next tests @@ -925,7 +891,8 @@ class Person page.save expect(page._slugs_translations).to eq('en' => ['title-on-english'], 'nl' => ['title-on-english']) - page = PageSlugLocalized.create(title_translations: { 'en' => 'Title on English2', 'nl' => 'Title on English2' }) + page = PageSlugLocalized.create(title_translations: { 'en' => 'Title on English2', + 'nl' => 'Title on English2' }) expect(page._slugs_translations).to eq('en' => ['title-on-english2'], 'nl' => ['title-on-english2']) end @@ -1047,16 +1014,16 @@ class Person # Turn on i18n fallback require 'i18n/backend/fallbacks' - I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) + I18n::Backend::Simple.include I18n::Backend::Fallbacks ::I18n.fallbacks[:nl] = %i[nl en] expect(page.slug).to eql 'title-on-english' fallback_slug = page.slug fallback_page = begin - PageSlugLocalizedHistory.find(fallback_slug) - rescue StandardError - nil - end + PageSlugLocalizedHistory.find(fallback_slug) + rescue StandardError + nil + end expect(fallback_page).to eq(page) end @@ -1067,8 +1034,8 @@ class Person page.title_translations = { 'en' => 'Modified Title on English', 'nl' => 'Modified Title on Netherlands' } page.save - expect(page._slugs_translations).to eq('en' => ['title-on-english', 'modified-title-on-english'], - 'nl' => ['title-on-netherlands', 'modified-title-on-netherlands']) + expect(page._slugs_translations).to eq('en' => %w[title-on-english modified-title-on-english], + 'nl' => %w[title-on-netherlands modified-title-on-netherlands]) end it 'does not produce duplicate slugs' do @@ -1106,7 +1073,7 @@ class Person page.save expect(page.title_translations).to eq('en' => 'Modified Title on English', 'nl' => 'Title on Netherlands') - expect(page._slugs_translations).to eq('en' => ['title-on-english', 'modified-title-on-english'], + expect(page._slugs_translations).to eq('en' => %w[title-on-english modified-title-on-english], 'nl' => ['title-on-netherlands']) end @@ -1125,7 +1092,7 @@ class Person page.save page.title_translations = { 'en' => 'Modified Title on English', 'nl' => 'Title on Netherlands' } page.save - expect(page._slugs_translations).to eq('en' => ['title-on-english', 'modified-title-on-english'], + expect(page._slugs_translations).to eq('en' => %w[title-on-english modified-title-on-english], 'nl' => ['title-on-netherlands']) end end @@ -1151,6 +1118,8 @@ class Person expect(Author.slug_max_length).to eq 256 end + # TODO: the max length should be strictly enforced to be X chars + # including the numbers. Currently numbers make it go over X. it 'enforces max length of slug' do author1 = Author.create!(last_name: 't' * 1024) expect(author1.slug.length).to eq 256 @@ -1162,6 +1131,18 @@ class Person expect(author3.slug.length).to eq 258 expect(author3.slug.ends_with?('tt-2')).to be true end + + it 'does not enforce max length if not set' do + book1 = Book.create!(title: 't' * 1024) + expect(book1.slug.length).to eq 1024 + expect(book1.slug.ends_with?('ttt')).to be true + book2 = Book.create!(title: 't' * 1024) + expect(book2.slug.length).to eq 1026 + expect(book2.slug.ends_with?('tt-1')).to be true + book3 = Book.create!(title: 't' * 1024) + expect(book3.slug.length).to eq 1026 + expect(book3.slug.ends_with?('tt-2')).to be true + end end context 'has_many / belongs_to' do diff --git a/spec/shared/indexes.rb b/spec/shared/indexes.rb index 3ec8b25..2b257a8 100644 --- a/spec/shared/indexes.rb +++ b/spec/shared/indexes.rb @@ -1,13 +1,9 @@ +# frozen_string_literal: true + shared_context 'with an index' do |key| - if Mongoid::Compatibility::Version.mongoid3? - let(:index) { subject.index_options[key] } - let(:index_keys) { key } - let(:index_options) { index } - else - let(:index) { subject.index_specifications.detect { |spec| spec.key == key } } - let(:index_keys) { index.key } - let(:index_options) { index.options } - end + let(:index) { subject.index_specifications.detect { |spec| spec.key == key } } + let(:index_keys) { index.key } + let(:index_options) { index.options } end shared_examples 'has an index' do |key, options| diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c14c647..1640a19 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,13 +1,13 @@ +# frozen_string_literal: true + require 'bundler/setup' require 'rspec' +require 'rspec/its' require 'uuid' -require 'awesome_print' require 'active_support' require 'active_support/deprecation' require 'mongoid' -require 'rspec/its' -require 'mongoid/compatibility' require File.expand_path '../lib/mongoid/slug', __dir__ @@ -30,7 +30,7 @@ def database_id end %w[models shared].each do |dir| - Dir["./spec/#{dir}/*.rb"].each { |f| require f } + Dir["./spec/#{dir}/*.rb"].sort.each { |f| require f } end I18n.available_locales = %i[en nl] @@ -40,7 +40,7 @@ def database_id c.before :all do Mongoid.logger.level = Logger::INFO - Mongo::Logger.logger.level = Logger::INFO if Mongoid::Compatibility::Version.mongoid5_or_newer? + Mongo::Logger.logger.level = Logger::INFO end c.before(:each) do @@ -48,14 +48,9 @@ def database_id Book.create_indexes AuthorPolymorphic.create_indexes BookPolymorphic.create_indexes - Mongoid::IdentityMap.clear if defined?(Mongoid::IdentityMap) end c.after(:each) do - if Mongoid::Compatibility::Version.mongoid3? || Mongoid::Compatibility::Version.mongoid4? - Mongoid.default_session.drop - else - Mongoid::Clients.default.database.drop - end + Mongoid::Clients.default.database.drop end end diff --git a/spec/tasks/mongoid_slug_rake_spec.rb b/spec/tasks/mongoid_slug_rake_spec.rb index 2e46d50..8b370df 100644 --- a/spec/tasks/mongoid_slug_rake_spec.rb +++ b/spec/tasks/mongoid_slug_rake_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rake' From 153889c17d989f539394c8e460ea53945bc75f95 Mon Sep 17 00:00:00 2001 From: Johnny Shields <27655+johnnyshields@users.noreply.github.com> Date: Mon, 18 Sep 2023 04:13:45 +0900 Subject: [PATCH 3/6] Add option for index: false (#271) --- lib/mongoid/slug.rb | 4 +++- spec/models/no_index.rb | 9 +++++++++ spec/mongoid/slug_spec.rb | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 spec/models/no_index.rb diff --git a/lib/mongoid/slug.rb b/lib/mongoid/slug.rb index 1be4199..e7b6d6c 100644 --- a/lib/mongoid/slug.rb +++ b/lib/mongoid/slug.rb @@ -18,6 +18,7 @@ module Slug included do cattr_accessor :slug_reserved_words, :slug_scope, + :slug_index, :slugged_attributes, :slug_url_builder, :slug_history, @@ -77,6 +78,7 @@ def slug(*fields, &block) options = fields.extract_options! self.slug_scope = options[:scope] + self.slug_index = options[:index].nil? ? true : options[:index] self.slug_reserved_words = options[:reserve] || Set.new(%w[new edit]) self.slugged_attributes = fields.map(&:to_s) self.slug_history = options[:history] @@ -87,7 +89,7 @@ def slug(*fields, &block) alias_attribute :slugs, :_slugs # Set indexes - unless embedded? + if slug_index && !embedded? Mongoid::Slug::IndexBuilder.build_indexes(self, slug_scope_key, slug_by_model_type, options[:localize]) end diff --git a/spec/models/no_index.rb b/spec/models/no_index.rb new file mode 100644 index 0000000..b734c38 --- /dev/null +++ b/spec/models/no_index.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class NoIndex + include Mongoid::Document + include Mongoid::Slug + field :title + + slug :title, index: false +end diff --git a/spec/mongoid/slug_spec.rb b/spec/mongoid/slug_spec.rb index 2fbcaa5..46c46f0 100644 --- a/spec/mongoid/slug_spec.rb +++ b/spec/mongoid/slug_spec.rb @@ -598,6 +598,11 @@ class Person it_should_behave_like 'has an index', { _slugs: 1 }, unique: true, sparse: true end + context 'when slug index is skipped' do + subject { NoIndex } + it_should_behave_like 'does not have an index', _slugs: 1 + end + context 'when slug is scoped by a reference association' do subject { Author } it_should_behave_like 'does not have an index', _slugs: 1 From b46fdddecac1ef43c613a229fca6eeac3e7b2e6d Mon Sep 17 00:00:00 2001 From: Johnny Shields <27655+johnnyshields@users.noreply.github.com> Date: Mon, 18 Sep 2023 05:09:01 +0900 Subject: [PATCH 4/6] Cleanup (#272) * Cleanup - Remove Mongoid::Danger - Fix Rubocop issues - CI coverage should includeMongoid 8 and Ruby 3.2 --- .github/workflows/test.yml | 15 +-- .rubocop.yml | 20 +++- .rubocop_todo.yml | 40 +------ CHANGELOG.md | 203 +++++++++++++++++--------------- Dangerfile | 3 - Gemfile | 17 +-- README.md | 2 +- lib/mongoid/slug.rb | 2 +- lib/mongoid/slug/unique_slug.rb | 8 +- lib/mongoid/slug/version.rb | 2 +- lib/tasks/mongoid_slug.rake | 2 +- mongoid-slug.gemspec | 8 +- spec/spec_helper.rb | 2 +- 13 files changed, 153 insertions(+), 171 deletions(-) delete mode 100644 Dangerfile diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a97250e..d6dc685 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,15 +12,13 @@ jobs: runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental }} strategy: + fail-fast: false matrix: - ruby: [2.5, 2.6, 2.7, 3.0, jruby, truffleruby] - mongoid: [7] + ruby: [2.7, 3.0, 3.1, 3.2, truffleruby] + mongoid: [7, 8] experimental: [false] include: - - ruby: 2.7 - mongoid: HEAD - experimental: true - - ruby: 3.0 + - ruby: 3.2 mongoid: HEAD experimental: true - ruby: head @@ -29,8 +27,11 @@ jobs: - ruby: head mongoid: HEAD experimental: true + - ruby: jruby + mongoid: 8 + experimental: true - ruby: jruby-head - mongoid: 7 + mongoid: 8 experimental: true - ruby: truffleruby-head mongoid: 7 diff --git a/.rubocop.yml b/.rubocop.yml index 8da7c7d..d9984b6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,10 +1,28 @@ inherit_from: .rubocop_todo.yml AllCops: - TargetRubyVersion: 2.5 + TargetRubyVersion: 2.7 NewCops: enable SuggestExtensions: false +Metrics/AbcSize: + Enabled: false + +Metrics/BlockLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/ModuleLength: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + Style/Documentation: Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index dd08ae7..f8f6580 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2021-08-11 17:20:10 UTC using RuboCop version 1.18.4. +# on 2023-09-17 18:58:11 UTC using RuboCop version 1.56.3. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -13,41 +13,3 @@ Lint/ConstantDefinitionInBlock: Exclude: - 'spec/mongoid/slug_spec.rb' - 'spec/tasks/mongoid_slug_rake_spec.rb' - -# Offense count: 4 -# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. -Metrics/AbcSize: - Max: 44 - -# Offense count: 24 -# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. -# IgnoredMethods: refine -Metrics/BlockLength: - Max: 525 - -# Offense count: 2 -# Configuration parameters: IgnoredMethods. -Metrics/CyclomaticComplexity: - Max: 10 - -# Offense count: 7 -# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. -Metrics/MethodLength: - Max: 23 - -# Offense count: 2 -# Configuration parameters: CountComments, CountAsOne. -Metrics/ModuleLength: - Max: 937 - -# Offense count: 1 -# Configuration parameters: IgnoredMethods. -Metrics/PerceivedComplexity: - Max: 11 - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AllowOnConstant. -Style/CaseEquality: - Exclude: - - 'lib/mongoid/slug/unique_slug.rb' diff --git a/CHANGELOG.md b/CHANGELOG.md index eba03ab..1edb779 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,261 +1,270 @@ -## 7.0.0 (Next) +## 7.0.1 (Next) * Your contribution here. -* [#268](https://github.com/mongoid/mongoid-slug/pull/268): Ensure localized slugs index expected localized slug fields - [@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) +* [#272](https://github.com/mongoid/mongoid-slug/pull/272): Drop support for Ruby prior to version 2.7 - [@johnnyshields](https://github.com/johnnyshields) +* [#272](https://github.com/mongoid/mongoid-slug/pull/272): Add CI coverage through Ruby 3.2 and Mongoid 8 - [@johnnyshields](https://github.com/johnnyshields) +* [#272](https://github.com/mongoid/mongoid-slug/pull/272): Remove mongoid-danger gem dependency - [@johnnyshields](https://github.com/johnnyshields) +* [#272](https://github.com/mongoid/mongoid-slug/pull/272): Fix various Rubocop issues - [@johnnyshields](https://github.com/johnnyshields) +* [#271](https://github.com/mongoid/mongoid-slug/pull/271): Add :index option to slug macro to disable auto-index - [@johnnyshields](https://github.com/johnnyshields) ## 6.0.1 (2021/08/12) -* [#266](https://github.com/mongoid/mongoid-slug/pull/266): Ensure localized slugs index expected localized slug fields - [@onomated](https://github.com/onomated), [@johnnyshields](https://github.com/johnnyshields). -* [#265](https://github.com/mongoid/mongoid-slug/pull/265): Add Github Actions and remove Travis CI - [@johnnyshields](https://github.com/kailan). -* [#255](https://github.com/mongoid/mongoid-slug/pull/255): Use mongoid::config#models in rake task, resolves #247 - [@kailan](https://github.com/kailan). +* [#268](https://github.com/mongoid/mongoid-slug/pull/268): Improvements to localized slugs - [@johnnyshields](https://github.com/johnnyshields) +* [#266](https://github.com/mongoid/mongoid-slug/pull/266): Ensure localized slugs index expected localized slug fields - [@onomated](https://github.com/onomated), [@johnnyshields](https://github.com/johnnyshields) +* [#265](https://github.com/mongoid/mongoid-slug/pull/265): Add Github Actions and remove Travis CI - [@johnnyshields](https://github.com/kailan) +* [#255](https://github.com/mongoid/mongoid-slug/pull/255): Use Mongoid::Config#models in rake task, resolves #247 - [@kailan](https://github.com/kailan) ## 6.0.0 (2018/09/17) -* [#252](https://github.com/mongoid/mongoid-slug/pull/252): Compatibility with Mongoid 7.0.0+ - [@kailan](https://github.com/kailan). +* [#252](https://github.com/mongoid/mongoid-slug/pull/252): Compatibility with Mongoid 7.0.0+ - [@kailan](https://github.com/kailan) ## 5.3.3 (2017/04/06) -* [#240](https://github.com/mongoid/mongoid-slug/pull/240): Fix: ensure we find the correct `BSON::Regexp::Raw` class - [@artfuldodger](https://github.com/artfuldodger). +* [#240](https://github.com/mongoid/mongoid-slug/pull/240): Fix: ensure we find the correct `BSON::Regexp::Raw` class - [@artfuldodger](https://github.com/artfuldodger) ## 5.3.2 (2017/04/03) -* [#234](https://github.com/mongoid/mongoid-slug/pull/234): Compatibility with Mongoid 6 - [@moodlemags](https://github.com/moodlemags), [@dblock](https://github.com/dblock). -* [#238](https://github.com/mongoid/mongoid-slug/pull/238): Use `BSON::Regexp::Raw` instead of Ruby's Regexp to avoid a performance hit - [@mzikherman](https://github.com/mzikherman). +* [#234](https://github.com/mongoid/mongoid-slug/pull/234): Compatibility with Mongoid 6 - [@moodlemags](https://github.com/moodlemags), [@dblock](https://github.com/dblock) +* [#238](https://github.com/mongoid/mongoid-slug/pull/238): Use `BSON::Regexp::Raw` instead of Ruby's Regexp to avoid a performance hit - [@mzikherman](https://github.com/mzikherman) ## 5.3.0 (2016/09/11) -* [#228](https://github.com/mongoid/mongoid-slug/pull/228): Moved to the [mongoid](http://mongoid.github.io) organization - [@dblock](https://github.com/dblock), [@digitalplaywright](https://github.com/digitalplaywright). -* [#166](https://github.com/mongoid/mongoid-slug/issues/166): Configure slug builder globally - [@anujaware](https://github.com/anujaware). -* [#209](https://github.com/mongoid/mongoid-slug/issues/209): Prefixed internal `Mongoid::Slug` class attributes with `slug_` to avoid conflicts - [@dblock](https://github.com/dblock). -* [#217](https://github.com/mongoid/mongoid-slug/issues/217): Fixed `mongoid_slug:set` rake task for Mongoid 6 - [@dblock](https://github.com/dblock). -* [#219](https://github.com/mongoid/mongoid-slug/pull/219): Mongoid HEAD and Rails 5.0.0.rc1 support - [@Fudoshiki](https://github.com/Fudoshiki). -* [#224](https://github.com/mongoid/mongoid-slug/pull/224): Use Danger, PR linter - [@dblock](https://github.com/dblock). -* [#222](https://github.com/mongoid/mongoid-slug/pull/225): Fix: `Mongo::Error::OperationFailure: E11000 duplicate key error index` error with blank slugs, default `_slugs` to `nil` instead of `[]` - [@dblock](https://github.com/dblock). -* [#172](https://github.com/mongoid/mongoid-slug/pull/172): Improved handling of unique and sparse index constraints - [@johnnyshields](https://github.com/johnnyshields). -* [#229](https://github.com/mongoid/mongoid-slug/pull/229): Upgraded to RuboCop 0.42.0 - [@dblock](https://github.com/dblock). +* [#228](https://github.com/mongoid/mongoid-slug/pull/228): Moved to the [mongoid](http://mongoid.github.io) organization - [@dblock](https://github.com/dblock), [@digitalplaywright](https://github.com/digitalplaywright) +* [#166](https://github.com/mongoid/mongoid-slug/issues/166): Configure slug builder globally - [@anujaware](https://github.com/anujaware) +* [#209](https://github.com/mongoid/mongoid-slug/issues/209): Prefixed internal `Mongoid::Slug` class attributes with `slug_` to avoid conflicts - [@dblock](https://github.com/dblock) +* [#217](https://github.com/mongoid/mongoid-slug/issues/217): Fixed `mongoid_slug:set` rake task for Mongoid 6 - [@dblock](https://github.com/dblock) +* [#219](https://github.com/mongoid/mongoid-slug/pull/219): Mongoid HEAD and Rails 5.0.0.rc1 support - [@Fudoshiki](https://github.com/Fudoshiki) +* [#224](https://github.com/mongoid/mongoid-slug/pull/224): Use Danger, PR linter - [@dblock](https://github.com/dblock) +* [#222](https://github.com/mongoid/mongoid-slug/pull/225): Fix: `Mongo::Error::OperationFailure: E11000 duplicate key error index` error with blank slugs, default `_slugs` to `nil` instead of `[]` - [@dblock](https://github.com/dblock) +* [#172](https://github.com/mongoid/mongoid-slug/pull/172): Improved handling of unique and sparse index constraints - [@johnnyshields](https://github.com/johnnyshields) +* [#229](https://github.com/mongoid/mongoid-slug/pull/229): Upgraded to RuboCop 0.42.0 - [@dblock](https://github.com/dblock) ## 5.2.0 (2016/01/03) -* [#204](https://github.com/mongoid/mongoid-slug/pull/204): The text portion of the slug is now truncated at `Mongoid::Slug::MONGO_INDEX_KEY_LIMIT_BYTES - 32` bytes by default and can be set via `max_length` - [@dblock](https://github.com/dblock). -* [#177](https://github.com/mongoid/mongoid-slug/issues/177): Added `mongoid_slug:set` rake task to set slug for legacy data - [@anuja-joshi](https://github.com/anuja-joshi). +* [#204](https://github.com/mongoid/mongoid-slug/pull/204): The text portion of the slug is now truncated at `Mongoid::Slug::MONGO_INDEX_KEY_LIMIT_BYTES - 32` bytes by default and can be set via `max_length` - [@dblock](https://github.com/dblock) +* [#177](https://github.com/mongoid/mongoid-slug/issues/177): Added `mongoid_slug:set` rake task to set slug for legacy data - [@anuja-joshi](https://github.com/anuja-joshi) ## 5.1.1 -* [#197](https://github.com/mongoid/mongoid-slug/pull/197): Compatibility with Mongoid 5.0.1, fix [MONGOID-4177](https://jira.mongodb.org/browse/MONGOID-4177) - [@dblock](https://github.com/dblock). +* [#197](https://github.com/mongoid/mongoid-slug/pull/197): Compatibility with Mongoid 5.0.1, fix [MONGOID-4177](https://jira.mongodb.org/browse/MONGOID-4177) - [@dblock](https://github.com/dblock) ## 5.1.0 -* [#194](https://github.com/mongoid/mongoid-slug/issues/194): Fixed compatibility with Mongoid::Observer - [@dblock](https://github.com/dblock). +* [#194](https://github.com/mongoid/mongoid-slug/issues/194): Fixed compatibility with Mongoid::Observer - [@dblock](https://github.com/dblock) ## 5.0.0 -* [#187](https://github.com/mongoid/mongoid-slug/pull/187): Mongoid 5 support - [@dblock](https://github.com/dblock). -* [#188](https://github.com/mongoid/mongoid-slug/pull/188): Removed deprecated name, _mongoid_slug_ - [@dblock](https://github.com/dblock). -* [#189](https://github.com/mongoid/mongoid-slug/pull/189): Implemented RuboCop - [@dblock](https://github.com/dblock). +* [#187](https://github.com/mongoid/mongoid-slug/pull/187): Mongoid 5 support - [@dblock](https://github.com/dblock) +* [#188](https://github.com/mongoid/mongoid-slug/pull/188): Removed deprecated name, _mongoid_slug_ - [@dblock](https://github.com/dblock) +* [#189](https://github.com/mongoid/mongoid-slug/pull/189): Implemented RuboCop - [@dblock](https://github.com/dblock) ## 4.0.0 -* [#179](https://github.com/mongoid/mongoid-slug/pull/179): Renamed gem to mongoid-slug - [@nofxx](https://github.com/nofxx). -* [#168](https://github.com/mongoid/mongoid-slug/pull/168): Finding a unique slug is now threadsafe - [@jaxesn](https://github.com/jaxesn). -* [#165](https://github.com/mongoid/mongoid-slug/pull/165): Fixed compatibility with Mongoid::Paranoia - [@johnnyshields](https://github.com/johnnyshields). +* [#179](https://github.com/mongoid/mongoid-slug/pull/179): Renamed gem to mongoid-slug - [@nofxx](https://github.com/nofxx) +* [#168](https://github.com/mongoid/mongoid-slug/pull/168): Finding a unique slug is now threadsafe - [@jaxesn](https://github.com/jaxesn) +* [#165](https://github.com/mongoid/mongoid-slug/pull/165): Fixed compatibility with Mongoid::Paranoia - [@johnnyshields](https://github.com/johnnyshields) ## 3.2.2 ## Bugfixes -* [#163](https://github.com/mongoid/mongoid-slug/pull/163): Avoid scope error in tests - [@johnnyshields](https://github.com/johnnyshields). -* Require activesupport dependencies to fix error in test on ruby 1.9.3 and Mongoid 4 - [@digitalplaywright](https://github.com/digitalplaywright). +* [#163](https://github.com/mongoid/mongoid-slug/pull/163): Avoid scope error in tests - [@johnnyshields](https://github.com/johnnyshields) +* Require activesupport dependencies to fix error in test on ruby 1.9.3 and Mongoid 4 - [@digitalplaywright](https://github.com/digitalplaywright) ## 3.2.1 ### Improvements -* Bumped Mongoid 4 requirement to beta1 - [@digitalplaywright](https://github.com/digitalplaywright). +* Bumped Mongoid 4 requirement to beta1 - [@digitalplaywright](https://github.com/digitalplaywright) ### Bugfixes -* Fixed Mongoid4 - [@blackxored](https://github.com/blackxored). -* Fixed translation tests - [@digitalplaywright](https://github.com/digitalplaywright). -* Added sparse option to slug index - [@klacointe](https://github.com/klacointe). +* Fixed Mongoid4 - [@blackxored](https://github.com/blackxored) +* Fixed translation tests - [@digitalplaywright](https://github.com/digitalplaywright) +* Added sparse option to slug index - [@klacointe](https://github.com/klacointe) ## 3.2.0 ### Improvements -* Updated stringex dependency to 2.0 or higher - [@digitalplaywright](https://github.com/digitalplaywright). -* Added Mongoid 4 support - [@dblock](https://github.com/dblock). +* Updated stringex dependency to 2.0 or higher - [@digitalplaywright](https://github.com/digitalplaywright) +* Added Mongoid 4 support - [@dblock](https://github.com/dblock) ### Bugfixes -* Fixed for when using localized slug with custom slug building strategy on virtual attrbitues - [@astjohn](https://github.com/astjohn). +* Fixed for when using localized slug with custom slug building strategy on virtual attrbitues - [@astjohn](https://github.com/astjohn) ## 3.1.2 ### Bugfixes -* Fixes for i8n slug generation - [@astjohn](https://github.com/astjohn). -* Don't use unique indexes with polymorphics - [@pdf](https://github.com/pdf). +* Fixes for i8n slug generation - [@astjohn](https://github.com/astjohn) +* Don't use unique indexes with polymorphics - [@pdf](https://github.com/pdf) ### Improvements -* Refactored of test cases - [@lucasrenan](https://github.com/lucasrenan). +* Refactored of test cases - [@lucasrenan](https://github.com/lucasrenan) ## 3.1.1 ### Bugfixes -* [#121](https://github.com/mongoid/mongoid-slug/issues/121), [#122](https://github.com/mongoid/mongoid-slug/issues/122): Do not generate empty slug - [@digitalplaywright](https://github.com/digitalplaywright). +* [#121](https://github.com/mongoid/mongoid-slug/issues/121), [#122](https://github.com/mongoid/mongoid-slug/issues/122): Do not generate empty slug - [@digitalplaywright](https://github.com/digitalplaywright) ## 3.1.0 ### New Features -* Optionally slugs are created and found per model type - [@joe1chen](https://github.com/joe1chen). +* Optionally slugs are created and found per model type - [@joe1chen](https://github.com/joe1chen) ### Bugfixes -* Fixed issue with default scope and slug uniqueness - [@loopj](https://github.com/loopj). +* Fixed issue with default scope and slug uniqueness - [@loopj](https://github.com/loopj) ## 3.0.0 ### Bugfixes -* Avoid using reserved words as slugs - [@deepakkumarnd](https://github.com/deepakkumarnd). -* Fixed localized slug creation when using history and when the locale changes after document is created - [@byscripts](https://github.com/byscripts). -* Improved specs for reserved words - [@astjohn](https://github.com/astjohn). -* Added Mongoid Paranoia specs - [@simi](https://github.com/simi). -* Fixed Mongoid Slug for Ruby 2.0.0 - [@digitalplaywright](https://github.com/digitalplaywright). +* Avoid using reserved words as slugs - [@deepakkumarnd](https://github.com/deepakkumarnd) +* Fixed localized slug creation when using history and when the locale changes after document is created - [@byscripts](https://github.com/byscripts) +* Improved specs for reserved words - [@astjohn](https://github.com/astjohn) +* Added Mongoid Paranoia specs - [@simi](https://github.com/simi) +* Fixed Mongoid Slug for Ruby 2.0.0 - [@digitalplaywright](https://github.com/digitalplaywright) ### New Features -* Made slugs localizable by option - [@xslim](https://github.com/xslim). +* Made slugs localizable by option - [@xslim](https://github.com/xslim) ## 2.0.1 ### Bugfixes -* Fix wrong homepage link in gemspec - [@digitalplaywright](https://github.com/digitalplaywright). +* Fix wrong homepage link in gemspec - [@digitalplaywright](https://github.com/digitalplaywright) ## 2.0.0 ### New Features -* Separated out unique finding logic into own class - [@guyboertje](https://github.com/guyboertje). -* Enabled custom specification of looks_like_slug? method - [@guyboertje](https://github.com/guyboertje). +* Separated out unique finding logic into own class - [@guyboertje](https://github.com/guyboertje) +* Enabled custom specification of looks_like_slug? method - [@guyboertje](https://github.com/guyboertje) ### Major Changes (Backwards Incompatible) -* Calling `to_param` on a document without a slug no longer builds a slug and persists the document - [@gerad](https://github.com/gerad). -* Removed transfer from history - [@guyboertje](https://github.com/guyboertje). +* Calling `to_param` on a document without a slug no longer builds a slug and persists the document - [@gerad](https://github.com/gerad) +* Removed transfer from history - [@guyboertje](https://github.com/guyboertje) ## 1.0.1 ### Bugfixes -* Do not create indexes for embedded documents - [@digitalplaywright](https://github.com/digitalplaywright). +* Do not create indexes for embedded documents - [@digitalplaywright](https://github.com/digitalplaywright) ## 1.0.0 ### Features -* Only look for a new unique slug if the existing slugs contains the current slug - [@digitalplaywright](https://github.com/digitalplaywright). +* Only look for a new unique slug if the existing slugs contains the current slug - [@digitalplaywright](https://github.com/digitalplaywright) ### Minor Changes -* [#76](https://github.com/mongoid/mongoid-slug/pull/76): Cleanup of callback handling - [@empact](https://github.com/empact). +* [#76](https://github.com/mongoid/mongoid-slug/pull/76): Cleanup of callback handling - [@empact](https://github.com/empact) ### Major Changes (Backwards Incompatible) -* Custom slug block now passes in the object - [@digitalplaywright](https://github.com/digitalplaywright). -* Fixed broken #find - [@al](https://github.com/al). -* Only Mongoid 3.0 syntax is supported - [@digitalplaywright](https://github.com/digitalplaywright). -* Store all slugs in a single field of array type - [@digitalplaywright](https://github.com/digitalplaywright). -* Removed the ':as' feature - [@digitalplaywright](https://github.com/digitalplaywright). -* Renamed slug field to _slugs - [@digitalplaywright](https://github.com/digitalplaywright). -* Slugs are indexes by default and removed the :index option - [@digitalplaywright](https://github.com/digitalplaywright). -* Reserved words should default to :new and :edit - [@digitalplaywright](https://github.com/digitalplaywright). -* Removed find_by_slug - [@digitalplaywright](https://github.com/digitalplaywright). -* Added `#find_by_slug!` - [@al](https://github.com/al). +* Custom slug block now passes in the object - [@digitalplaywright](https://github.com/digitalplaywright) +* Fixed broken #find - [@al](https://github.com/al) +* Only Mongoid 3.0 syntax is supported - [@digitalplaywright](https://github.com/digitalplaywright) +* Store all slugs in a single field of array type - [@digitalplaywright](https://github.com/digitalplaywright) +* Removed the ':as' feature - [@digitalplaywright](https://github.com/digitalplaywright) +* Renamed slug field to _slugs - [@digitalplaywright](https://github.com/digitalplaywright) +* Slugs are indexes by default and removed the :index option - [@digitalplaywright](https://github.com/digitalplaywright) +* Reserved words should default to :new and :edit - [@digitalplaywright](https://github.com/digitalplaywright) +* Removed find_by_slug - [@digitalplaywright](https://github.com/digitalplaywright) +* Added `#find_by_slug!` - [@al](https://github.com/al) ### Bugfixes -* Corrected index creation on scoped slugs - [@DouweM](https://github.com/DouweM). +* Corrected index creation on scoped slugs - [@DouweM](https://github.com/DouweM) ## 0.10.0 -* Fixed Slug history should only apply if history is set to true - [@tomaswitek](https://github.com/tomaswitek). -* Fixed Model.slug should alias to to_param - [@tomaswitek](https://github.com/tomaswitek). -* Added .find_unique_slug_for and #find_unique_slug_for methods - [@DouweM](https://github.com/DouweM). -* Ensured uniqueness of slug set manually - [@DouweM](https://github.com/DouweM). -* Added support for reserved slugs - [@siong1987](https://github.com/siong1987), [@DouweM](https://github.com/DouweM). -* Added support for keeping a history of slugs - [@DouweM](https://github.com/DouweM). -* Added by_slug(slug) scope - [@DouweM](https://github.com/DouweM). -* Allowed set slug on aliased field - [@eagleas](https://github.com/eagleas). +* Fixed Slug history should only apply if history is set to true - [@tomaswitek](https://github.com/tomaswitek) +* Fixed Model.slug should alias to to_param - [@tomaswitek](https://github.com/tomaswitek) +* Added .find_unique_slug_for and #find_unique_slug_for methods - [@DouweM](https://github.com/DouweM) +* Ensured uniqueness of slug set manually - [@DouweM](https://github.com/DouweM) +* Added support for reserved slugs - [@siong1987](https://github.com/siong1987), [@DouweM](https://github.com/DouweM) +* Added support for keeping a history of slugs - [@DouweM](https://github.com/DouweM) +* Added by_slug(slug) scope - [@DouweM](https://github.com/DouweM) +* Allowed set slug on aliased field - [@eagleas](https://github.com/eagleas) ## 0.9.0 -* [#43](https://github.com/mongoid/mongoid-slug/pull/43): Allowed overriding of slug at model creation time - [@bdmac](https://github.com/bdmac). +* [#43](https://github.com/mongoid/mongoid-slug/pull/43): Allowed overriding of slug at model creation time - [@bdmac](https://github.com/bdmac) ## 0.8.3 -* Bumped version of Stringex dependency - [@digitalplaywright](https://github.com/digitalplaywright). +* Bumped version of Stringex dependency - [@digitalplaywright](https://github.com/digitalplaywright) ## 0.8.2 -* Generated a slug when an existing document does not have one - [@digitalplaywright](https://github.com/digitalplaywright). +* Generated a slug when an existing document does not have one - [@digitalplaywright](https://github.com/digitalplaywright) ## 0.8.1 -* [#27](https://github.com/mongoid/mongoid-slug/pull/27): No longer necessary to require library in Gemfile - [@etehtsea](https://github.com/etehtsea). +* [#27](https://github.com/mongoid/mongoid-slug/pull/27): No longer necessary to require library in Gemfile - [@etehtsea](https://github.com/etehtsea) ## 0.8.0 -* [#23](https://github.com/mongoid/mongoid-slug/pull/23): Fix edbug concerning slugs with double-digit counters - [@jbredeche](https://github.com/jbredeche). -* Removed #slug!. The method is of limited value - [@digitalplaywright](https://github.com/digitalplaywright). +* [#23](https://github.com/mongoid/mongoid-slug/pull/23): Fix edbug concerning slugs with double-digit counters - [@jbredeche](https://github.com/jbredeche) +* Removed #slug!. The method is of limited value - [@digitalplaywright](https://github.com/digitalplaywright) ## 0.7.2 -* [#21](https://github.com/mongoid/mongoid-slug/pull/21): Added `#find_by_slug!` - [@ajsharp](https://github.com/ajsharp). +* [#21](https://github.com/mongoid/mongoid-slug/pull/21): Added `#find_by_slug!` - [@ajsharp](https://github.com/ajsharp) ## 0.7.1 -* [#16](https://github.com/mongoid/mongoid-slug/pull/16): Library no longers hit database multiple times to find unique slug when duplicates exist - [@tiendung](https://github.com/tiendung). +* [#16](https://github.com/mongoid/mongoid-slug/pull/16): Library no longers hit database multiple times to find unique slug when duplicates exist - [@tiendung](https://github.com/tiendung) ## 0.7.0 -* Slug now can be given an optional block to build a custom slug out of the specified fields - [@digitalplaywright](https://github.com/digitalplaywright). +* Slug now can be given an optional block to build a custom slug out of the specified fields - [@digitalplaywright](https://github.com/digitalplaywright) ## 0.6.4 -* [#10](https://github.com/mongoid/mongoid-slug/pull/10): Added :any option to use first present field when multiple fields are slugged - [@iamnader](https://github.com/iamnader). +* [#10](https://github.com/mongoid/mongoid-slug/pull/10): Added :any option to use first present field when multiple fields are slugged - [@iamnader](https://github.com/iamnader) ## 0.6.3 -* [#13](https://github.com/mongoid/mongoid-slug/pull/13): Mongoid no longer requires that emmbedded_in pass `:inverse_of` option - [@sporkd](https://github.com/sporkd). +* [#13](https://github.com/mongoid/mongoid-slug/pull/13): Mongoid no longer requires that emmbedded_in pass `:inverse_of` option - [@sporkd](https://github.com/sporkd) ## 0.6.2 -* Added #slug! to generate slug for an existing document - [@digitalplaywright](https://github.com/digitalplaywright). +* Added #slug! to generate slug for an existing document - [@digitalplaywright](https://github.com/digitalplaywright) ## 0.6.1 -* Added support for STI models - [@dmathieu](https://github.com/dmathieu). +* Added support for STI models - [@dmathieu](https://github.com/dmathieu) ## 0.6.0 -* Fixed internals to work with Mongoid RC - [@digitalplaywright](https://github.com/digitalplaywright). -* Finder is now dynamic - [@digitalplaywright](https://github.com/digitalplaywright). +* Fixed internals to work with Mongoid RC - [@digitalplaywright](https://github.com/digitalplaywright) +* Finder is now dynamic - [@digitalplaywright](https://github.com/digitalplaywright) ## 0.5.1 -* Added support for scoping by reference association - [@ches](https://github.com/ches). -* Brought indexing back in as an option - [@digitalplaywright](https://github.com/digitalplaywright). +* Added support for scoping by reference association - [@ches](https://github.com/ches) +* Brought indexing back in as an option - [@digitalplaywright](https://github.com/digitalplaywright) ## 0.5.0 -* Added support for non-Latin languages - [@etehtsea](https://github.com/etehtsea). -* Removed :scoped. Embedded objects are now scoped by parent by default - [@digitalplaywright](https://github.com/digitalplaywright). -* Added finder method - [@digitalplaywright](https://github.com/digitalplaywright). +* Added support for non-Latin languages - [@etehtsea](https://github.com/etehtsea) +* Removed :scoped. Embedded objects are now scoped by parent by default - [@digitalplaywright](https://github.com/digitalplaywright) +* Added finder method - [@digitalplaywright](https://github.com/digitalplaywright) ## Earlier tags -* To be found in the dustbin of git log - [@digitalplaywright](https://github.com/digitalplaywright). +* To be found in the dustbin of git log - [@digitalplaywright](https://github.com/digitalplaywright) diff --git a/Dangerfile b/Dangerfile deleted file mode 100644 index de2a4a0..0000000 --- a/Dangerfile +++ /dev/null @@ -1,3 +0,0 @@ -# frozen_string_literal: true - -danger.import_dangerfile(gem: 'mongoid-danger') diff --git a/Gemfile b/Gemfile index d6f3782..17ccaec 100644 --- a/Gemfile +++ b/Gemfile @@ -4,17 +4,18 @@ source 'https://rubygems.org' gemspec name: 'mongoid-slug' -case version = ENV['MONGOID_VERSION'] || '7' +case (version = ENV['MONGOID_VERSION'] || '8') when 'HEAD' gem 'mongoid', github: 'mongodb/mongoid' -when /^7/ - gem 'mongoid', '~> 7' +when /\A\d+\z/ + gem 'mongoid', "~> #{version}.0" else gem 'mongoid', version end -group :test do - gem 'mongoid-danger', '~> 0.1.0', require: false - gem 'rubocop', '~> 1.18.4' - gem 'rubocop-rspec' -end +gem 'rake' +gem 'rspec' +gem 'rspec-its' +gem 'rubocop' +gem 'rubocop-rspec' +gem 'uuid' diff --git a/README.md b/README.md index 36e8bdf..0cceb57 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ It sits idly on top of [stringex](https://github.com/rsl/stringex), supporting n ### Version Support -Mongoid Slug 7.x requires at least Mongoid 7.0.0 and Ruby 2.5.0. For earlier Mongoid and Ruby version support, please use an earlier version of Mongoid Slug. +Mongoid Slug 7.x requires at least Mongoid 7.0.0 and Ruby 2.7.0. For earlier Mongoid and Ruby version support, please use an earlier version of Mongoid Slug. Mongoid Slug is compatible with all MongoDB versions which Mongoid supports, however, please see "Slug Max Length" section below for MongoDB 4.0 and earlier. diff --git a/lib/mongoid/slug.rb b/lib/mongoid/slug.rb index e7b6d6c..93e853c 100644 --- a/lib/mongoid/slug.rb +++ b/lib/mongoid/slug.rb @@ -185,7 +185,7 @@ def apply_slug # skip slug generation and use Mongoid id # to find document instead - return true if new_slug.size.zero? + return true if new_slug.empty? # avoid duplicate slugs _slugs&.delete(new_slug) diff --git a/lib/mongoid/slug/unique_slug.rb b/lib/mongoid/slug/unique_slug.rb index 471b4bd..4596a29 100644 --- a/lib/mongoid/slug/unique_slug.rb +++ b/lib/mongoid/slug/unique_slug.rb @@ -23,11 +23,9 @@ def initialize(slug, documents, pattern) history_slugs = doc._slugs next if history_slugs.nil? - existing_slugs.push(*history_slugs.find_all { |cur_slug| cur_slug =~ regexp_pattern }) + existing_slugs.push(*history_slugs.grep(regexp_pattern)) last_entered_slug.push(*history_slugs.last) if history_slugs.last =~ regexp_pattern - existing_history_slugs.push(*history_slugs.first(history_slugs.length - 1).find_all do |cur_slug| - cur_slug =~ regexp_pattern - end) + existing_history_slugs.push(*history_slugs.first(history_slugs.length - 1).grep(regexp_pattern)) end end @@ -116,7 +114,7 @@ def find_unique(attempt = nil) @state.include_slug unless model.class.look_like_slugs?([@_slug]) # make sure that the slug is not equal to a reserved word - @state.include_slug if slug_reserved_words.any? { |word| word === @_slug } + @state.include_slug if slug_reserved_words.any? { |word| word === @_slug } # rubocop:disable Style/CaseEquality # only look for a new unique slug if the existing slugs contains the current slug # - e.g if the slug 'foo-2' is taken, but 'foo' is available, the user can use 'foo'. diff --git a/lib/mongoid/slug/version.rb b/lib/mongoid/slug/version.rb index 1d4f848..e4eac64 100644 --- a/lib/mongoid/slug/version.rb +++ b/lib/mongoid/slug/version.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Mongoid #:nodoc: +module Mongoid # :nodoc: module Slug VERSION = '7.0.0' end diff --git a/lib/tasks/mongoid_slug.rake b/lib/tasks/mongoid_slug.rake index dea5148..b338230 100644 --- a/lib/tasks/mongoid_slug.rake +++ b/lib/tasks/mongoid_slug.rake @@ -3,7 +3,7 @@ namespace :mongoid_slug do desc 'Goes though all documents and sets slug if not already set' task set: :environment do |_, args| - ::Rails.application.eager_load! if defined?(Rails) + Rails.application.eager_load! if defined?(Rails) klasses = Mongoid::Config.models.find_all { |c| c.ancestors.include?(Mongoid::Slug) } unless klasses.blank? models = args.extras diff --git a/mongoid-slug.gemspec b/mongoid-slug.gemspec index 34fb83e..23d9158 100644 --- a/mongoid-slug.gemspec +++ b/mongoid-slug.gemspec @@ -14,16 +14,12 @@ Gem::Specification.new do |s| s.description = 'Mongoid URL slug or permalink generator' s.license = 'MIT' - s.required_ruby_version = '>= 2.5' + s.required_ruby_version = '>= 2.7' s.add_dependency 'mongoid', '>= 7.0' s.add_dependency 'stringex', '~> 2.0' - s.add_development_dependency 'rake' - s.add_development_dependency 'rspec' - s.add_development_dependency 'rspec-its' - s.add_development_dependency 'uuid' s.files = Dir.glob('lib/**/*') + %w[LICENSE README.md] - s.test_files = Dir.glob('spec/**/*') s.require_paths = ['lib'] + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1640a19..ce43a00 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -38,7 +38,7 @@ def database_id RSpec.configure do |c| c.raise_errors_for_deprecations! - c.before :all do + c.before(:all) do Mongoid.logger.level = Logger::INFO Mongo::Logger.logger.level = Logger::INFO end From 6b6ad2f07f4772f5615dc8492c3ba870afb017c5 Mon Sep 17 00:00:00 2001 From: Johnny Shields <27655+johnnyshields@users.noreply.github.com> Date: Mon, 18 Sep 2023 05:21:11 +0900 Subject: [PATCH 5/6] Add note about indexes to README --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 0cceb57..358c613 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ post = Post.find 'a-thousand-plateaus' # Finds by slugs post = Post.find '50b1386a0482939864000001' # Finds by bson ids => ... ``` + [Examine slug.rb](lib/mongoid/slug.rb) for all available options. ### Updating Existing Records @@ -133,6 +134,23 @@ The `to_url` method comes from [stringex](https://github.com/rsl/stringex). You can define a slug builder globally and/or override it per model. +### Indexing + +By default, Mongoid Slug will automatically generate an index for the slug, which will be created when you run `rake db:create_indexes`. This index will take into account scoping and other options described below. + +To skip this index generation, you may set `index: false` as follows: + +```ruby +class Employee + include Mongoid::Document + include Mongoid::Slug + + field :name + + slug :name, index: :false +end +``` + ### Scoping To scope a slug by a reference association, pass `:scope`: From c52831e9483e4e2d4f53705c14ee38e3229653d8 Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 21 Apr 2024 04:55:44 +0300 Subject: [PATCH 6/6] add multi-field scoping for slugs (#274) * add multiple scopes support * upd changelog and readme * fix some comments * refactor array iterations * fix compound indexes * rename for clarity * fix readme * Update README.md * Update slug.rb --------- Co-authored-by: Johnny Shields <27655+johnnyshields@users.noreply.github.com> --- CHANGELOG.md | 3 +- README.md | 16 +++++++ lib/mongoid/slug.rb | 28 +++++++++---- lib/mongoid/slug/index_builder.rb | 5 ++- lib/mongoid/slug/unique_slug.rb | 65 ++++++++++++++++++++++------- lib/mongoid/slug/version.rb | 2 +- spec/models/page_with_categories.rb | 15 +++++++ spec/mongoid/index_builder_spec.rb | 29 +++++++++++++ spec/mongoid/slug_spec.rb | 48 +++++++++++++++++++++ spec/spec_helper.rb | 1 + 10 files changed, 184 insertions(+), 28 deletions(-) create mode 100644 spec/models/page_with_categories.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 1edb779..3afffd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ -## 7.0.1 (Next) +## 7.1.0 (Next) +* [#274](https://github.com/mongoid/mongoid-slug/pull/274): Added support for scoping slugs by multiple fields - [@mikekosulin](https://github.com/mikekosulin) * Your contribution here. ## 7.0.0 (2023/09/18) diff --git a/README.md b/README.md index 358c613..41f880e 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,22 @@ class Employee end ``` +You may scope slugs using multiple fields as per the following example: + +```ruby +class Employee + include Mongoid::Document + include Mongoid::Slug + + field :name + field :company_id + field :department_id + + # Scope slug uniqueness by a combination of company and department + slug :name, scope: %i[company_id department_id] +end +``` + ### Slug Max Length MongoDB [featureCompatibilityVersion](https://docs.mongodb.com/manual/reference/command/setFeatureCompatibilityVersion/#std-label-view-fcv) diff --git a/lib/mongoid/slug.rb b/lib/mongoid/slug.rb index 93e853c..1f34b49 100644 --- a/lib/mongoid/slug.rb +++ b/lib/mongoid/slug.rb @@ -57,9 +57,10 @@ module ClassMethods # @param options [Boolean] :permanent Whether the slug should be # immutable. Defaults to `false`. # @param options [Array] :reserve` A list of reserved slugs - # @param options :scope [Symbol] a reference association or field to - # scope the slug by. Embedded documents are, by default, scoped by - # their parent. + # @param options :scope [Symbol, Array] a reference association, field, + # or array of fields to scope the slug by. + # Embedded documents are, by default, scoped by their parent. Now it supports not only + # a single association or field but also an array of them. # @param options :max_length [Integer] the maximum length of the text portion of the slug # @yield If given, a block is used to build a slug. # @@ -90,8 +91,7 @@ def slug(*fields, &block) # Set indexes if slug_index && !embedded? - Mongoid::Slug::IndexBuilder.build_indexes(self, slug_scope_key, slug_by_model_type, - options[:localize]) + Mongoid::Slug::IndexBuilder.build_indexes(self, slug_scope_keys, slug_by_model_type, options[:localize]) end self.slug_url_builder = block_given? ? block : default_slug_url_builder @@ -113,13 +113,23 @@ def look_like_slugs?(*args) with_default_scope.look_like_slugs?(*args) end - # Returns the scope key for indexing, considering associations + def slug_scopes + # If slug_scope is set (i.e., not nil), we convert it to an array to ensure we can handle it consistently. + # If it's not set, we use an array with a single nil element, signifying no specific scope. + slug_scope ? Array(slug_scope) : [nil] + end + + # Returns the scope keys for indexing, considering associations # # @return [ Array, Document ] - def slug_scope_key + def slug_scope_keys return nil unless slug_scope - reflect_on_association(slug_scope).try(:key) || slug_scope + # If slug_scope is an array, we map over its elements to get each individual scope's key. + slug_scopes.map do |individual_scope| + # Attempt to find the association and get its key. If no association is found, use the scope as-is. + reflect_on_association(individual_scope).try(:key) || individual_scope + end end # Find documents by slugs. @@ -297,7 +307,7 @@ def new_with_slugs? def persisted_with_slug_changes? if localized? changes = _slugs_change - return (persisted? && false) if changes.nil? + return false if changes.nil? # ensure we check for changes only between the same locale original = changes.first.try(:fetch, I18n.locale.to_s, nil) diff --git a/lib/mongoid/slug/index_builder.rb b/lib/mongoid/slug/index_builder.rb index 8158f8d..c6e000d 100644 --- a/lib/mongoid/slug/index_builder.rb +++ b/lib/mongoid/slug/index_builder.rb @@ -8,7 +8,7 @@ module IndexBuilder # Creates indexes on a document for a given slug scope # # @param [ Mongoid::Document ] doc The document on which to create the index(es) - # @param [ String or Symbol ] scope_key The optional scope key for the index(es) + # @param [ String or Symbol or Array ] scope_key The optional scope key for the index(es) # @param [ Boolean ] by_model_type Whether or not to use single table inheritance # @param [ Boolean or Array ] localize The locale for localized index field # @@ -28,7 +28,8 @@ def build_index(doc, scope_key = nil, by_model_type = false, locale = nil) # See: http://docs.mongodb.org/manual/core/index-compound/ fields = {} fields[:_type] = 1 if by_model_type - fields[scope_key] = 1 if scope_key + + Array(scope_key).each { |key| fields[key] = 1 } locale = ::I18n.default_locale if locale.is_a?(TrueClass) if locale diff --git a/lib/mongoid/slug/unique_slug.rb b/lib/mongoid/slug/unique_slug.rb index 4596a29..3132129 100644 --- a/lib/mongoid/slug/unique_slug.rb +++ b/lib/mongoid/slug/unique_slug.rb @@ -100,10 +100,12 @@ def find_unique(attempt = nil) where_hash[:_slugs.all] = [regex_for_slug] where_hash[:_id.ne] = model._id - if (scope = slug_scope) && reflect_on_association(scope).nil? + Array(slug_scope).each do |individual_scope| + next unless reflect_on_association(individual_scope).nil? + # scope is not an association, so it's scoped to a local field # (e.g. an association id in a denormalized db design) - where_hash[scope] = model.try(:read_attribute, scope) + where_hash[individual_scope] = model.try(:read_attribute, individual_scope) end where_hash[:_type] = model.try(:read_attribute, :_type) if slug_by_model_type @@ -143,26 +145,59 @@ def regex_for_slug end def uniqueness_scope - if slug_scope && (metadata = reflect_on_association(slug_scope)) - - parent = model.send(metadata.name) - - # Make sure doc is actually associated with something, and that - # some referenced docs have been persisted to the parent - # - # TODO: we need better reflection for reference associations, - # like association_name instead of forcing collection_name here - # -- maybe in the forthcoming Mongoid refactorings? - inverse = metadata.inverse_of || collection_name - return parent.respond_to?(inverse) ? parent.send(inverse) : model.class + # If slug_scope is present, we need to handle whether it's a single scope or multiple scopes. + if slug_scope + # We'll track individual scope results in an array. + scope_results = [] + + Array(slug_scope).each do |individual_scope| + next unless (metadata = reflect_on_association(individual_scope)) + + # For each scope, we identify its association metadata and fetch the parent record. + parent = model.send(metadata.name) + + # It's important to handle nil cases if the parent record doesn't exist. + if parent.nil? + # You might want to handle this scenario differently based on your application's logic. + next + end + + # Make sure doc is actually associated with something, and that + # some referenced docs have been persisted to the parent + # + # TODO: we need better reflection for reference associations, + # like association_name instead of forcing collection_name here + # -- maybe in the forthcoming Mongoid refactorings? + inverse = metadata.inverse_of || collection_name + next unless parent.respond_to?(inverse) + + # Add the associated records of the parent (based on the inverse) to our results. + scope_results << parent.send(inverse) + end + + # After iterating through all scopes, we need to decide how to combine the results (if there are multiple). + # This part depends on how your application should treat multiple scopes. + # Here, we'll simply return the first non-empty scope result as an example. + scope_results.each do |result| + return result if result.present? # or any other logic for selecting among multiple scope results + end + + # If we reach this point, it means no valid parent scope was found (all were nil or didn't match the + # conditions). + # You might want to raise an error, return a default scope, or handle this scenario based on your + # application's logic. + # For this example, we're returning the model's class as a default. + return model.class end + # The rest of your method remains unchanged, handling cases where slug_scope isn't defined. + # This is your existing logic for embedded models or deeper superclass retrieval. if embedded? parent_metadata = reflect_on_all_association(:embedded_in)[0] return model._parent.send(parent_metadata.inverse_of || self.metadata.name) end - # unless embedded or slug scope, return the deepest document superclass + # Unless embedded or slug scope, return the deepest document superclass. appropriate_class = model.class appropriate_class = appropriate_class.superclass while appropriate_class.superclass.include?(Mongoid::Document) appropriate_class diff --git a/lib/mongoid/slug/version.rb b/lib/mongoid/slug/version.rb index e4eac64..6ccf1bb 100644 --- a/lib/mongoid/slug/version.rb +++ b/lib/mongoid/slug/version.rb @@ -2,6 +2,6 @@ module Mongoid # :nodoc: module Slug - VERSION = '7.0.0' + VERSION = '7.1.0' end end diff --git a/spec/models/page_with_categories.rb b/spec/models/page_with_categories.rb new file mode 100644 index 0000000..12e38e4 --- /dev/null +++ b/spec/models/page_with_categories.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class PageWithCategories + include Mongoid::Document + include Mongoid::Slug + field :title + field :content + + field :page_category + field :page_sub_category + + field :order, type: Integer + slug :title, scope: %i[page_category page_sub_category] + default_scope -> { asc(:order) } +end diff --git a/spec/mongoid/index_builder_spec.rb b/spec/mongoid/index_builder_spec.rb index 3ec3aef..c782767 100644 --- a/spec/mongoid/index_builder_spec.rb +++ b/spec/mongoid/index_builder_spec.rb @@ -51,6 +51,35 @@ end end + context 'when scope_key is set and is array' do + let(:doc) do + Class.new do + include Mongoid::Document + field :title, type: String + field :page_category, type: String + field :page_sub_category, type: String + end + end + let(:scope_key) { %i[page_category page_sub_category] } + + before do + doc.field :page_category, type: String + doc.field :page_sub_category, type: String + + Mongoid::Slug::IndexBuilder.build_indexes(doc, scope_key, by_model_type, locales) + end + + context 'when by_model_type is true' do + let(:by_model_type) { true } + + it { is_expected.to eq [[{ _slugs: 1, page_category: 1, page_sub_category: 1, _type: 1 }, {}]] } + end + + context 'when by_model_type is false' do + it { is_expected.to eq [[{ _slugs: 1, page_category: 1, page_sub_category: 1 }, {}]] } + end + end + context 'when scope_key is not set' do context 'when by_model_type is true' do let(:by_model_type) { true } diff --git a/spec/mongoid/slug_spec.rb b/spec/mongoid/slug_spec.rb index 46c46f0..a54ce32 100644 --- a/spec/mongoid/slug_spec.rb +++ b/spec/mongoid/slug_spec.rb @@ -163,6 +163,54 @@ module Mongoid end end + context 'when the object has multiple scopes' do + let(:category1) { 'category1' } + let(:category2) { 'category2' } + let(:sub_category1) { 'sub_category1' } + let(:sub_category2) { 'sub_category2' } + let(:common_title) { 'Common Title' } + + context 'when pages have the same title and different categories' do + it 'creates pages with the same slug' do + page1 = PageWithCategories.create!(title: common_title, page_category: category1) + page2 = PageWithCategories.create!(title: common_title, page_category: category2) + + expect(page1.slug).to eq(page2.slug) + end + end + + context 'when pages have the same title and same category but different sub-categories' do + it 'creates pages with the same slug' do + page1 = PageWithCategories.create!(title: common_title, page_category: category1, + page_sub_category: sub_category1) + page2 = PageWithCategories.create!(title: common_title, page_category: category1, + page_sub_category: sub_category2) + + expect(page1.slug).to eq(page2.slug) + end + end + + context 'when pages have the same title, same category, and same sub-category' do + it 'creates pages with different slugs' do + page1 = PageWithCategories.create!(title: common_title, page_category: category1, + page_sub_category: sub_category1) + page2 = PageWithCategories.create!(title: common_title, page_category: category1, + page_sub_category: sub_category1) + + expect(page1.slug).not_to eq(page2.slug) + end + end + + context 'when pages have the same title and same category, without sub-categories' do + it 'creates pages with different slugs' do + page1 = PageWithCategories.create!(title: common_title, page_category: category1) + page2 = PageWithCategories.create!(title: common_title, page_category: category1) + + expect(page1.slug).not_to eq(page2.slug) + end + end + end + context 'when the object is embedded' do let(:subject) do book.subjects.create(name: 'Psychoanalysis') diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ce43a00..e2e5fb1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -48,6 +48,7 @@ def database_id Book.create_indexes AuthorPolymorphic.create_indexes BookPolymorphic.create_indexes + PageWithCategories.create_indexes end c.after(:each) do