mongoid-slug 5.1.1 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f62313ab069384e3dea183cd680aae50318beb85
4
- data.tar.gz: 8881c0bef60727f9c57d8210b74f04bd48f545d6
3
+ metadata.gz: 2d38815d369307746d6c796167d08b99aae02f8d
4
+ data.tar.gz: e0f6c6ba7dc2431fe84de87a6b32dcc90ba1f2ba
5
5
  SHA512:
6
- metadata.gz: 0bbf0cc529c6c8da1955ab3f9d40dfddb5e081c740bee1f012b3c115ad1698ed00bd5c8b81e158ce3626678e99dc9337a565ea3a8c67107583e940d20eed78f7
7
- data.tar.gz: d9b4553651b7c2f588a8fe188974c1074283846dae8e5962d05471b216d50e7dc0db1ae10bad7ed46c932debf502ea28ebe7e1726fa1360866cbb9da802add49
6
+ metadata.gz: c4a7f3f5d7fdf36cb4d64b0ae5bb9f1e35bc6c2dbad3a7d1bbd586ff46b0a0da957bd3762bbe88182595b1aeb9b4e59c6a88bd143bbcdc3f17498c1a60ff82be
7
+ data.tar.gz: c91cb32733b81ec8b1ace9528bfced0c019aa1fc96d88cc4b6e11d803af0509cee3a0098260de8abcfd7702207deda9cd1c813b3f73f3a12f14930880d08c94c
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2015 Hakan Ensari & Contributors
1
+ Copyright (c) 2010-2016 Hakan Ensari & Contributors
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -60,7 +60,7 @@ class Post
60
60
  field :_id, type: String, slug_id_strategy: lambda {|id| id.start_with?('....')}
61
61
 
62
62
  field :name
63
- slug :name, :history => true
63
+ slug :name, history: true
64
64
  end
65
65
 
66
66
  Post.fields['_id'].type
@@ -72,6 +72,16 @@ post = Post.find '50b1386a0482939864000001' # Finds by bson ids
72
72
  ```
73
73
  [Examine slug.rb](lib/mongoid/slug.rb) for all available options.
74
74
 
75
+ To set slugs for existing records run following rake task:
76
+
77
+ ```ruby
78
+ rake mongoid_slug:set
79
+ ```
80
+ You can pass model names as an option for which you want to set slugs:
81
+
82
+ ```ruby
83
+ rake mongoid_slug:set[Model1,Model2]
84
+ ```
75
85
  Custom Slug Generation
76
86
  -------
77
87
 
@@ -111,7 +121,7 @@ class Employee
111
121
  field :name
112
122
  referenced_in :company
113
123
 
114
- slug :name, :scope => :company
124
+ slug :name, scope: :company
115
125
  end
116
126
  ```
117
127
 
@@ -133,12 +143,28 @@ class Employee
133
143
  field :name
134
144
  field :company_id
135
145
 
136
- slug :name, :scope => :company_id
146
+ slug :name, scope: :company_id
137
147
  end
138
148
  ```
139
149
 
140
- Optionally find and create slugs per model type
141
- -------
150
+ Limit Slug Length
151
+ -----------------
152
+
153
+ 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`.
154
+
155
+ ```ruby
156
+ class Company
157
+ include Mongoid::Document
158
+ include Mongoid::Slug
159
+
160
+ field :name
161
+
162
+ slug :name, max_length: 24
163
+ end
164
+ ```
165
+
166
+ Optionally Find and Create Slugs per Model Type
167
+ -----------------------------------------------
142
168
 
143
169
  By default when using STI, the scope will be around the super-class.
144
170
 
@@ -148,7 +174,7 @@ class Book
148
174
  include Mongoid::Slug
149
175
  field :title
150
176
 
151
- slug :title, :history => true
177
+ slug :title, history: true
152
178
  embeds_many :subjects
153
179
  has_many :authors
154
180
  end
@@ -156,12 +182,12 @@ end
156
182
  class ComicBook < Book
157
183
  end
158
184
 
159
- book = Book.create(:title => "Anti Oedipus")
160
- comic_book = ComicBook.create(:title => "Anti Oedipus")
185
+ book = Book.create(title: 'Anti Oedipus')
186
+ comic_book = ComicBook.create(title: 'Anti Oedipus')
161
187
  comic_book.slugs.should_not eql(book.slugs)
162
188
  ```
163
189
 
164
- If you want the scope to be around the subclass, then set the option :by_model_type => true.
190
+ If you want the scope to be around the subclass, then set the option `by_model_type: true`.
165
191
 
166
192
  ```ruby
167
193
  class Book
@@ -169,7 +195,7 @@ class Book
169
195
  include Mongoid::Slug
170
196
  field :title
171
197
 
172
- slug :title, :history => true, :by_model_type => true
198
+ slug :title, history: true, by_model_type: true
173
199
  embeds_many :subjects
174
200
  has_many :authors
175
201
  end
@@ -177,8 +203,8 @@ end
177
203
  class ComicBook < Book
178
204
  end
179
205
 
180
- book = Book.create(:title => "Anti Oedipus")
181
- comic_book = ComicBook.create(:title => "Anti Oedipus")
206
+ book = Book.create(title: 'Anti Oedipus')
207
+ comic_book = ComicBook.create(title: 'Anti Oedipus')
182
208
  comic_book.slugs.should eql(book.slugs)
183
209
  ```
184
210
 
@@ -206,7 +232,7 @@ page = Page.new title: "Home"
206
232
  page.save
207
233
  page.update_attributes title: "Welcome"
208
234
 
209
- Page.find("welcome") == Page.find("home") #=> true
235
+ Page.find("welcome") == Page.find("home") # => true
210
236
  ```
211
237
 
212
238
  Reserved Slugs
@@ -276,7 +302,7 @@ class Entity
276
302
  field :_id, type: String, slug_id_strategy: UuidIdStrategy
277
303
 
278
304
  field :user_edited_variation
279
- slug :user_edited_variation, :history => true
305
+ slug :user_edited_variation, history: true
280
306
  end
281
307
  ```
282
308
 
@@ -329,5 +355,5 @@ Mongoid-slug is work of [many of contributors](https://github.com/digitalplaywri
329
355
  Copyright & License
330
356
  -------------------
331
357
 
332
- Copyright (c) 2010-2015 Hakan Ensari & Contributors, see [LICENSE](LICENSE) for details.
358
+ Copyright (c) 2010-2016 Hakan Ensari & Contributors, see [LICENSE](LICENSE) for details.
333
359
 
@@ -6,19 +6,23 @@ require 'mongoid/slug/paranoia'
6
6
  require 'mongoid/slug/unique_slug'
7
7
  require 'mongoid/slug/slug_id_strategy'
8
8
  require 'mongoid-compatibility'
9
+ require 'mongoid/slug/railtie' if defined?(Rails)
9
10
 
10
11
  module Mongoid
11
12
  # Slugs your Mongoid model.
12
13
  module Slug
13
14
  extend ActiveSupport::Concern
14
15
 
16
+ MONGO_INDEX_KEY_LIMIT_BYTES = 1024
17
+
15
18
  included do
16
19
  cattr_accessor :reserved_words,
17
20
  :slug_scope,
18
21
  :slugged_attributes,
19
22
  :url_builder,
20
23
  :history,
21
- :by_model_type
24
+ :by_model_type,
25
+ :slug_max_length
22
26
 
23
27
  # field :_slugs, type: Array, default: [], localize: false
24
28
  # alias_attribute :slugs, :_slugs
@@ -43,6 +47,7 @@ module Mongoid
43
47
  # @param options :scope [Symbol] a reference association or field to
44
48
  # scope the slug by. Embedded documents are, by default, scoped by
45
49
  # their parent.
50
+ # @param options :max_length [Integer] the maximum length of the text portion of the slug
46
51
  # @yield If given, a block is used to build a slug.
47
52
  #
48
53
  # @example A custom builder
@@ -64,6 +69,7 @@ module Mongoid
64
69
  self.slugged_attributes = fields.map(&:to_s)
65
70
  self.history = options[:history]
66
71
  self.by_model_type = options[:by_model_type]
72
+ self.slug_max_length = options.key?(:max_length) ? options[:max_length] : MONGO_INDEX_KEY_LIMIT_BYTES - 32
67
73
 
68
74
  field :_slugs, type: Array, default: [], localize: options[:localize]
69
75
  alias_attribute :slugs, :_slugs
@@ -0,0 +1,9 @@
1
+ module Mongoid
2
+ module Slug
3
+ class Railtie < Rails::Railtie
4
+ rake_tasks do
5
+ Dir[File.join(File.dirname(__FILE__), '../../tasks/*.rake')].each { |f| load f }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -63,7 +63,7 @@ module Mongoid
63
63
 
64
64
  def_delegators :@model, :slug_scope, :reflect_on_association, :read_attribute,
65
65
  :check_against_id, :reserved_words, :url_builder, :collection_name,
66
- :embedded?, :reflect_on_all_associations, :by_model_type
66
+ :embedded?, :reflect_on_all_associations, :by_model_type, :slug_max_length
67
67
 
68
68
  def initialize(model)
69
69
  @model = model
@@ -82,6 +82,9 @@ module Mongoid
82
82
  else
83
83
  url_builder.call(model)
84
84
  end
85
+
86
+ @_slug = @_slug[0...slug_max_length] if slug_max_length
87
+
85
88
  # Regular expression that matches slug, slug-1, ... slug-n
86
89
  # If slug_name field was indexed, MongoDB will utilize that
87
90
  # index to match /^.../ pattern.
@@ -1,5 +1,5 @@
1
1
  module Mongoid #:nodoc:
2
2
  module Slug
3
- VERSION = '5.1.1'
3
+ VERSION = '5.2.0'
4
4
  end
5
5
  end
@@ -0,0 +1,18 @@
1
+ namespace :mongoid_slug do
2
+ desc 'Goes though all documents and sets slug if not already set'
3
+ task set: :environment do |_, args|
4
+ ::Rails.application.eager_load! if defined?(Rails)
5
+ klasses = Module.constants.find_all do |const|
6
+ const != const.upcase ? Mongoid::Slug > (Object.const_get const) : nil
7
+ end
8
+ klasses.map! { |klass| klass.to_s.constantize }
9
+ unless klasses.blank?
10
+ models = args.extras
11
+ klasses = (klasses.map(&:to_s) & models.map(&:classify)).map(&:constantize) if models.any?
12
+ klasses.each do |klass|
13
+ # set slug for objects having blank slug
14
+ klass.each { |object| object.set_slug! unless object.slugs? }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -3,7 +3,7 @@ class Author
3
3
  include Mongoid::Slug
4
4
  field :first_name
5
5
  field :last_name
6
- slug :first_name, :last_name, scope: :book
6
+ slug :first_name, :last_name, scope: :book, history: false, max_length: 256
7
7
  belongs_to :book
8
8
  has_many :characters,
9
9
  class_name: 'Person',
@@ -3,7 +3,7 @@ class Book
3
3
  include Mongoid::Slug
4
4
  field :title
5
5
 
6
- slug :title, history: true
6
+ slug :title, history: true, max_length: nil
7
7
  embeds_many :subjects
8
8
  has_many :authors
9
9
  end
@@ -348,33 +348,50 @@ module Mongoid
348
348
  end
349
349
 
350
350
  context 'when :history is passed as an argument' do
351
- let(:book) do
352
- Book.create(title: 'Book Title')
353
- end
351
+ context 'true' do
352
+ let(:book) do
353
+ Book.create(title: 'Book Title')
354
+ end
354
355
 
355
- before(:each) do
356
- book.title = 'Other Book Title'
357
- book.save
358
- end
356
+ before(:each) do
357
+ book.title = 'Other Book Title'
358
+ book.save
359
+ end
359
360
 
360
- it "saves the old slug in the owner's history" do
361
- expect(book.slugs).to include('book-title')
362
- end
361
+ it "saves the old slug in the owner's history" do
362
+ expect(book.slugs).to include('book-title')
363
+ end
363
364
 
364
- it 'generates a unique slug by appending a counter to duplicate text' do
365
- dup = Book.create(title: 'Book Title')
366
- expect(dup.to_param).to eql 'book-title-1'
367
- end
365
+ it 'generates a unique slug by appending a counter to duplicate text' do
366
+ dup = Book.create(title: 'Book Title')
367
+ expect(dup.to_param).to eql 'book-title-1'
368
+ end
368
369
 
369
- it 'does not allow a BSON::ObjectId as use for a slug' do
370
- bad = Book.create(title: '4ea0389f0364313d79104fb3')
371
- expect(bad.to_param).not_to eql '4ea0389f0364313d79104fb3'
370
+ it 'does not allow a BSON::ObjectId as use for a slug' do
371
+ bad = Book.create(title: '4ea0389f0364313d79104fb3')
372
+ expect(bad.to_param).not_to eql '4ea0389f0364313d79104fb3'
373
+ end
374
+
375
+ it 'ensures no duplicate values are stored in history' do
376
+ book.update_attributes title: 'Book Title'
377
+ book.update_attributes title: 'Foo'
378
+ expect(book.slugs.find_all { |slug| slug == 'book-title' }.size).to eql 1
379
+ end
372
380
  end
381
+ context 'false' do
382
+ let(:author) do
383
+ Author.create(first_name: 'Gilles', last_name: 'Deleuze')
384
+ end
373
385
 
374
- it 'ensures no duplicate values are stored in history' do
375
- book.update_attributes title: 'Book Title'
376
- book.update_attributes title: 'Foo'
377
- expect(book.slugs.find_all { |slug| slug == 'book-title' }.size).to eql 1
386
+ before(:each) do
387
+ author.first_name = 'John'
388
+ author.save
389
+ end
390
+
391
+ it "does not save the old slug in the owner's history" do
392
+ expect(author.slugs.count).to eq 1
393
+ expect(author.slugs).to_not include('gilles-deleuze')
394
+ end
378
395
  end
379
396
  end
380
397
 
@@ -519,6 +536,28 @@ module Mongoid
519
536
  it_should_behave_like 'has an index', { _slugs: 1 }, unique: true, sparse: true
520
537
  end
521
538
 
539
+ context 'with a value exceeding mongodb max index key' do
540
+ if Mongoid::Compatibility::Version.mongoid5?
541
+ it 'errors with a model without a max length' do
542
+ expect do
543
+ Book.create!(title: 't' * 1025)
544
+ end.to raise_error Mongo::Error::OperationFailure, /key too large to index/
545
+ end
546
+ elsif Mongoid::Compatibility::Version.mongoid4?
547
+ it 'errors with a model without a max length' do
548
+ expect do
549
+ Book.create!(title: 't' * 1025)
550
+ end.to raise_error Moped::Errors::OperationFailure, /key too large to index/
551
+ end
552
+ end
553
+ it 'succeeds with a model with a max length' do
554
+ expect do
555
+ author = Author.create!(last_name: 't' * 1025)
556
+ expect(author.slug.length).to eq 256
557
+ end.to_not raise_error
558
+ end
559
+ end
560
+
522
561
  context 'when slug is scoped by a reference association' do
523
562
  subject { Author }
524
563
  it_should_behave_like 'does not have an index', _slugs: 1
@@ -1019,5 +1058,34 @@ module Mongoid
1019
1058
  'nl' => ['title-on-netherlands'])
1020
1059
  end
1021
1060
  end
1061
+
1062
+ describe 'slug_max_length' do
1063
+ before do
1064
+ Author.create_indexes
1065
+ end
1066
+ after do
1067
+ Author.remove_indexes
1068
+ end
1069
+ it 'can be assigned to nil' do
1070
+ expect(Book.slug_max_length).to be nil
1071
+ end
1072
+ it 'defaults to MONGO_INDEX_KEY_LIMIT_BYTES - 32' do
1073
+ expect(Article.slug_max_length).to eq Mongoid::Slug::MONGO_INDEX_KEY_LIMIT_BYTES - 32
1074
+ end
1075
+ it 'is assigned via max_length' do
1076
+ expect(Author.slug_max_length).to eq 256
1077
+ end
1078
+ it 'enforces max length of slug' do
1079
+ author1 = Author.create!(last_name: 't' * 1024)
1080
+ expect(author1.slug.length).to eq 256
1081
+ expect(author1.slug.ends_with?('ttt')).to be true
1082
+ author2 = Author.create!(last_name: 't' * 1024)
1083
+ expect(author2.slug.length).to eq 258
1084
+ expect(author2.slug.ends_with?('tt-1')).to be true
1085
+ author3 = Author.create!(last_name: 't' * 1024)
1086
+ expect(author3.slug.length).to eq 258
1087
+ expect(author3.slug.ends_with?('tt-2')).to be true
1088
+ end
1089
+ end
1022
1090
  end
1023
1091
  end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+ require 'rake'
3
+
4
+ describe 'mongoid_slug:set' do
5
+ before :all do
6
+ load File.expand_path('../../../lib/tasks/mongoid_slug.rake', __FILE__)
7
+ Rake::Task.define_task(:environment)
8
+ end
9
+
10
+ context 'when models parameter is passed' do
11
+ before :all do
12
+ UninitalizedSlugFirst = Class.new do
13
+ include Mongoid::Document
14
+ field :name, type: String
15
+ store_in collection: 'uninitalized_slug_first'
16
+ end
17
+ UninitalizedSlugSecond = Class.new do
18
+ include Mongoid::Document
19
+ field :name, type: String
20
+ store_in collection: 'uninitalized_slug_second'
21
+ end
22
+ end
23
+
24
+ it 'goes though all documents of passed models and sets slug if not already set' do
25
+ uninitalized_slug1 = UninitalizedSlugFirst.create(name: 'uninitalized-slug1')
26
+ uninitalized_slug2 = UninitalizedSlugSecond.create(name: 'uninitalized-slug2')
27
+
28
+ UninitalizedSlugFirst.class_eval do
29
+ include Mongoid::Slug
30
+ slug :name
31
+ end
32
+ UninitalizedSlugSecond.class_eval do
33
+ include Mongoid::Slug
34
+ slug :name
35
+ end
36
+
37
+ expect(uninitalized_slug1.slugs).to be_nil
38
+ expect(uninitalized_slug2.slugs).to be_nil
39
+
40
+ Rake::Task['mongoid_slug:set'].reenable
41
+ Rake::Task['mongoid_slug:set'].invoke('UninitalizedSlugFirst')
42
+
43
+ expect(uninitalized_slug1.reload.slugs).to eq(['uninitalized-slug1'])
44
+ expect(uninitalized_slug2.reload.slugs).to eq []
45
+ end
46
+ end
47
+
48
+ context 'when models parameter is not passed' do
49
+ before :all do
50
+ UninitalizedSlugThird = Class.new do
51
+ include Mongoid::Document
52
+ field :name, type: String
53
+ store_in collection: 'uninitalized_slug_third'
54
+ end
55
+ end
56
+
57
+ it 'goes though all documents and sets slug if not already set' do
58
+ uninitalized_slug3 = UninitalizedSlugThird.create(name: 'uninitalized-slug3')
59
+
60
+ UninitalizedSlugThird.class_eval do
61
+ include Mongoid::Slug
62
+ slug :name
63
+ end
64
+
65
+ expect(uninitalized_slug3.slugs).to be_nil
66
+
67
+ Rake::Task['mongoid_slug:set'].reenable
68
+ Rake::Task['mongoid_slug:set'].invoke
69
+
70
+ expect(uninitalized_slug3.reload.slugs).to eq(['uninitalized-slug3'])
71
+ end
72
+ end
73
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-slug
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.1
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Saebjoernsen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-03 00:00:00.000000000 Z
11
+ date: 2016-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mongoid
@@ -177,10 +177,12 @@ files:
177
177
  - lib/mongoid/slug/criteria.rb
178
178
  - lib/mongoid/slug/index.rb
179
179
  - lib/mongoid/slug/paranoia.rb
180
+ - lib/mongoid/slug/railtie.rb
180
181
  - lib/mongoid/slug/slug_id_strategy.rb
181
182
  - lib/mongoid/slug/unique_slug.rb
182
183
  - lib/mongoid/slug/version.rb
183
184
  - lib/mongoid_slug.rb
185
+ - lib/tasks/mongoid_slug.rake
184
186
  - spec/models/alias.rb
185
187
  - spec/models/article.rb
186
188
  - spec/models/artist.rb
@@ -215,6 +217,7 @@ files:
215
217
  - spec/mongoid/slug_spec.rb
216
218
  - spec/shared/indexes.rb
217
219
  - spec/spec_helper.rb
220
+ - spec/tasks/mongoid_slug_rake_spec.rb
218
221
  homepage: https://github.com/digitalplaywright/mongoid-slug
219
222
  licenses:
220
223
  - MIT
@@ -274,3 +277,4 @@ test_files:
274
277
  - spec/mongoid/slug_spec.rb
275
278
  - spec/shared/indexes.rb
276
279
  - spec/spec_helper.rb
280
+ - spec/tasks/mongoid_slug_rake_spec.rb