mongoid_slug 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -39,7 +39,9 @@ module Mongoid #:nodoc:
39
39
  #
40
40
  # * `:index`, which specifies whether an index should be defined for the
41
41
  # slug. Defaults to `false` and has no effect if the document is em-
42
- # bedded.
42
+ # bedded. Make sure you have a unique index on the slug of root
43
+ # documents to avoid the (very unlikely) race condition that would ensue
44
+ # if two documents with identical slugs were to be saved simultaneously.
43
45
  #
44
46
  # Alternatively, this method can be given a block to build a custom slug
45
47
  # out of the specified fields.
@@ -59,9 +61,9 @@ module Mongoid #:nodoc:
59
61
  # end
60
62
  #
61
63
  def slug(*fields, &block)
62
- options = fields.extract_options!
63
- self.slug_scope = options[:scope]
64
- self.slug_name = options[:as] || :slug
64
+ options = fields.extract_options!
65
+ self.slug_scope = options[:scope]
66
+ self.slug_name = options[:as] || :slug
65
67
  self.slugged_fields = fields.map(&:to_s)
66
68
 
67
69
  self.slug_builder =
@@ -69,7 +71,7 @@ module Mongoid #:nodoc:
69
71
  block
70
72
  else
71
73
  lambda do |doc|
72
- slugged_fields.map { |f| doc.read_attribute(f) }.join(',')
74
+ slugged_fields.map { |f| doc.read_attribute(f) }.join(' ')
73
75
  end
74
76
  end
75
77
 
@@ -94,20 +96,13 @@ module Mongoid #:nodoc:
94
96
  end
95
97
 
96
98
  def self.find_by_#{slug_name}!(slug)
97
- where(slug_name => slug).first || raise(Mongoid::Errors::DocumentNotFound.new(self.class, slug))
99
+ where(slug_name => slug).first ||
100
+ raise(Mongoid::Errors::DocumentNotFound.new(self.class, slug))
98
101
  end
99
102
  CODE
100
103
  end
101
104
  end
102
105
 
103
- # Regenerates slug.
104
- #
105
- # Should come in handy when generating slugs for an existing collection.
106
- def slug!
107
- generate_slug!
108
- save
109
- end
110
-
111
106
  # Returns the slug.
112
107
  def to_param
113
108
  read_attribute(slug_name)
@@ -116,20 +111,29 @@ module Mongoid #:nodoc:
116
111
  private
117
112
 
118
113
  def find_unique_slug
114
+ # TODO: An epic method which calls for refactoring.
119
115
  slug = slug_builder.call(self).to_url
120
-
116
+
121
117
  # Regular expression that matches slug, slug-1, slug-2, ... slug-n
122
118
  # If slug_name field was indexed, MongoDB will utilize that index to
123
119
  # match /^.../ pattern
124
- pattern = /^#{Regexp.escape(slug)}(?:-\d+)?$/
120
+ pattern = /^#{Regexp.escape(slug)}(?:-(\d+))?$/
125
121
 
126
- # Get the maximum counter slug
127
- max_counter_slug = uniqueness_scope.only(slug_name).
122
+ existing_slugs =
123
+ uniqueness_scope.
124
+ only(slug_name).
128
125
  where(slug_name => pattern, :_id.ne => _id).
129
- order_by([slug_name, :desc]).first.try(:read_attribute, slug_name)
126
+ map {|obj| obj.try(:read_attribute, slug_name)}
130
127
 
131
- if max_counter_slug
132
- max_counter = max_counter_slug.match(/-(\d+)$/).try(:[], 1).to_i
128
+ if existing_slugs.count > 0
129
+ # sort the existing_slugs in increasing order by comparing the suffix
130
+ # numbers:
131
+ # slug, slug-1, slug-2, ..., slug-n
132
+ existing_slugs.sort! do |a, b|
133
+ (pattern.match(a)[1] || -1).to_i <=> (pattern.match(b)[1] || -1).to_i
134
+ end
135
+ max_counter = existing_slugs.last.match(/-(\d+)$/).try(:[], 1).to_i
136
+
133
137
  # Use max_counter + 1 as unique counter
134
138
  slug += "-#{max_counter + 1}"
135
139
  end
@@ -1,5 +1,5 @@
1
1
  module Mongoid #:nodoc:
2
2
  module Slug
3
- VERSION = '0.7.2'
3
+ VERSION = '0.8.0'
4
4
  end
5
5
  end
@@ -0,0 +1,9 @@
1
+ class Page
2
+ include Mongoid::Document
3
+ include Mongoid::Slug
4
+ field :title
5
+ field :content
6
+ field :order, :type => Integer
7
+ slug :title
8
+ default_scope asc(:order)
9
+ end
@@ -19,8 +19,10 @@ module Mongoid
19
19
  end
20
20
 
21
21
  it "generates a unique slug by appending a counter to duplicate text" do
22
- dup = Book.create(:title => book.title)
23
- dup.to_param.should eql "a-thousand-plateaus-1"
22
+ 15.times{ |x|
23
+ dup = Book.create(:title => book.title)
24
+ dup.to_param.should eql "a-thousand-plateaus-#{x+1}"
25
+ }
24
26
  end
25
27
 
26
28
  it "does not update slug if slugged fields have not changed" do
@@ -39,6 +41,12 @@ module Mongoid
39
41
  end
40
42
  end
41
43
 
44
+ context "when using default_scope on a model" do
45
+ it "find_unique_slug should work correctly" do
46
+ Page.create!(:title => "Title", :content => "Content", :order => 1)
47
+ end
48
+ end
49
+
42
50
  context "when the object is embedded" do
43
51
  let(:subject) do
44
52
  book.subjects.create(:name => "Psychoanalysis")
@@ -322,32 +330,6 @@ module Mongoid
322
330
  end
323
331
  end
324
332
 
325
- describe "#slug!" do
326
- before do
327
- class Foo
328
- include Mongoid::Document
329
- field :name
330
- end
331
- end
332
-
333
- let!(:foo) do
334
- Foo.create(:name => "John")
335
- end
336
-
337
- it "regenerates slug" do
338
- class Foo
339
- include Mongoid::Slug
340
- slug :name
341
- end
342
-
343
- foo.reload.slug.should be_nil
344
-
345
- foo.slug!
346
-
347
- foo.reload.slug.should eql 'john'
348
- end
349
- end
350
-
351
333
  describe ".find_by_slug" do
352
334
  let!(:book) { Book.create(:title => "A Thousand Plateaus") }
353
335
 
@@ -15,7 +15,7 @@ require File.expand_path("../../lib/mongoid/slug", __FILE__)
15
15
 
16
16
  Dir["#{File.dirname(__FILE__)}/models/*.rb"].each { |f| require f }
17
17
 
18
- Rspec.configure do |c|
18
+ RSpec.configure do |c|
19
19
  c.before(:all) { DatabaseCleaner.strategy = :truncation }
20
20
  c.before(:each) { DatabaseCleaner.clean }
21
21
  end
metadata CHANGED
@@ -1,8 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid_slug
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.7.2
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 8
8
+ - 0
9
+ version: 0.8.0
6
10
  platform: ruby
7
11
  authors:
8
12
  - Paper Cavalier
@@ -10,7 +14,7 @@ autorequire:
10
14
  bindir: bin
11
15
  cert_chain: []
12
16
 
13
- date: 2011-04-14 00:00:00 +01:00
17
+ date: 2011-06-10 00:00:00 +01:00
14
18
  default_executable:
15
19
  dependencies:
16
20
  - !ruby/object:Gem::Dependency
@@ -21,7 +25,10 @@ dependencies:
21
25
  requirements:
22
26
  - - ~>
23
27
  - !ruby/object:Gem::Version
24
- version: 2.0.0
28
+ segments:
29
+ - 2
30
+ - 0
31
+ version: "2.0"
25
32
  type: :runtime
26
33
  version_requirements: *id001
27
34
  - !ruby/object:Gem::Dependency
@@ -32,9 +39,40 @@ dependencies:
32
39
  requirements:
33
40
  - - ~>
34
41
  - !ruby/object:Gem::Version
35
- version: 1.2.0
42
+ segments:
43
+ - 1
44
+ - 2
45
+ version: "1.2"
36
46
  type: :runtime
37
47
  version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: database_cleaner
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ - 6
59
+ version: "0.6"
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 2
72
+ - 6
73
+ version: "2.6"
74
+ type: :development
75
+ version_requirements: *id004
38
76
  description: Mongoid Slug generates a URL slug or permalink based on one or more fields in a Mongoid model.
39
77
  email:
40
78
  - code@papercavalier.com
@@ -54,6 +92,7 @@ files:
54
92
  - spec/models/book.rb
55
93
  - spec/models/caption.rb
56
94
  - spec/models/comic_book.rb
95
+ - spec/models/page.rb
57
96
  - spec/models/partner.rb
58
97
  - spec/models/person.rb
59
98
  - spec/models/relationship.rb
@@ -74,17 +113,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
113
  requirements:
75
114
  - - ">="
76
115
  - !ruby/object:Gem::Version
116
+ segments:
117
+ - 0
77
118
  version: "0"
78
119
  required_rubygems_version: !ruby/object:Gem::Requirement
79
120
  none: false
80
121
  requirements:
81
122
  - - ">="
82
123
  - !ruby/object:Gem::Version
124
+ segments:
125
+ - 0
83
126
  version: "0"
84
127
  requirements: []
85
128
 
86
129
  rubyforge_project: mongoid_slug
87
- rubygems_version: 1.5.2
130
+ rubygems_version: 1.3.7
88
131
  signing_key:
89
132
  specification_version: 3
90
133
  summary: Generates a URL slug
@@ -94,6 +137,7 @@ test_files:
94
137
  - spec/models/book.rb
95
138
  - spec/models/caption.rb
96
139
  - spec/models/comic_book.rb
140
+ - spec/models/page.rb
97
141
  - spec/models/partner.rb
98
142
  - spec/models/person.rb
99
143
  - spec/models/relationship.rb