mongoid_slug 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +39 -1
- data/lib/mongoid/slug.rb +37 -6
- data/lib/mongoid/slug/version.rb +1 -1
- data/spec/models/author.rb +4 -1
- data/spec/models/book.rb +1 -1
- data/spec/models/person.rb +2 -1
- data/spec/mongoid/slug_spec.rb +88 -0
- metadata +18 -3
data/README.md
CHANGED
@@ -51,6 +51,44 @@ To demo some more functionality in the console:
|
|
51
51
|
>> author = book.authors.create(:first_name => "Gilles", :last_name => "Deleuze")
|
52
52
|
>> author.to_param
|
53
53
|
=> "gilles-deleuze"
|
54
|
-
>> author.update_attributes(:
|
54
|
+
>> author.update_attributes(:first_name => "Félix", :last_name => "Guattari")
|
55
55
|
>> author.to_param
|
56
56
|
=> "felix-guattari"
|
57
|
+
|
58
|
+
Scoping by Associations
|
59
|
+
-----------------------
|
60
|
+
|
61
|
+
Objects that are embedded in a parent document automatically have their slug uniqueness scoped to the parent. If you wish to scope by a reference association, you can pass a `:scope` option to the `slug` class method:
|
62
|
+
|
63
|
+
class Company
|
64
|
+
include Mongoid::Document
|
65
|
+
field :name
|
66
|
+
references_many :employees
|
67
|
+
end
|
68
|
+
|
69
|
+
class Employee
|
70
|
+
include Mongoid::Document
|
71
|
+
include Mongoid::Slug
|
72
|
+
field :first_name
|
73
|
+
field :last_name
|
74
|
+
slug :first_name, :last_name, :scope => :company
|
75
|
+
referenced_in :company
|
76
|
+
end
|
77
|
+
|
78
|
+
In this example, if you create an employee without associating it with any company, the slug scope will fall back to the root employees collection. Currently if you have an irregular association name, for instance:
|
79
|
+
|
80
|
+
references_many :employees, :class_name => 'Person', :foreign_key => :company_id
|
81
|
+
|
82
|
+
you **must** specify the `:inverse_of` option on the other side of the assocation.
|
83
|
+
|
84
|
+
Indexing
|
85
|
+
--------
|
86
|
+
|
87
|
+
You may optionally pass an `:index` option to generate an index on the slug in top-level objects.
|
88
|
+
|
89
|
+
class Book
|
90
|
+
field :title
|
91
|
+
slug :title, :index => true
|
92
|
+
end
|
93
|
+
|
94
|
+
Indexes on non-scoped slugs will be unique.
|
data/lib/mongoid/slug.rb
CHANGED
@@ -9,7 +9,7 @@ module Mongoid #:nodoc:
|
|
9
9
|
extend ActiveSupport::Concern
|
10
10
|
|
11
11
|
included do
|
12
|
-
cattr_accessor :slug_name, :slugged_fields
|
12
|
+
cattr_accessor :slug_name, :slugged_fields, :slug_scope
|
13
13
|
end
|
14
14
|
|
15
15
|
module ClassMethods
|
@@ -20,14 +20,30 @@ module Mongoid #:nodoc:
|
|
20
20
|
# alternative name with the :as option.
|
21
21
|
#
|
22
22
|
# If you wish the slug to be permanent once created, set :permanent to true.
|
23
|
+
#
|
24
|
+
# To index slug in a top-level object, set :index to true.
|
23
25
|
def slug(*fields)
|
24
26
|
options = fields.extract_options!
|
25
27
|
|
26
28
|
self.slug_name = options[:as] || :slug
|
29
|
+
self.slug_scope = options[:scope] || nil
|
27
30
|
self.slugged_fields = fields
|
28
31
|
|
32
|
+
if options[:scoped]
|
33
|
+
ActiveSupport::Deprecation.warn <<-EOM
|
34
|
+
|
35
|
+
The :scoped => true option is deprecated and now default for embedded
|
36
|
+
child documents. Please use :scope => :association_name if you wish
|
37
|
+
to scope by a reference association.
|
38
|
+
EOM
|
39
|
+
end
|
40
|
+
|
29
41
|
field slug_name
|
30
42
|
|
43
|
+
if options[:index]
|
44
|
+
index slug_name, :unique => (slug_scope ? false : true)
|
45
|
+
end
|
46
|
+
|
31
47
|
if options[:permanent]
|
32
48
|
before_create :generate_slug
|
33
49
|
else
|
@@ -86,14 +102,29 @@ module Mongoid #:nodoc:
|
|
86
102
|
end
|
87
103
|
|
88
104
|
def unique_slug?(slug)
|
89
|
-
|
105
|
+
uniqueness_scope.where(slug_name => slug).
|
106
|
+
reject { |doc| doc.id == self.id }.
|
107
|
+
empty?
|
108
|
+
end
|
109
|
+
|
110
|
+
def uniqueness_scope
|
111
|
+
if slug_scope
|
112
|
+
metadata = self.class.reflect_on_association(slug_scope)
|
113
|
+
parent = self.send(metadata.name)
|
114
|
+
|
115
|
+
# Make sure doc is actually associated with something, and that some
|
116
|
+
# referenced docs have been persisted to the parent
|
117
|
+
#
|
118
|
+
# TODO: we need better reflection for reference associations, like
|
119
|
+
# association_name instead of forcing collection_name here -- maybe
|
120
|
+
# in the forthcoming Mongoid refactorings?
|
121
|
+
inverse = metadata.inverse_of || collection_name
|
122
|
+
parent.respond_to?(inverse) ? parent.send(inverse) : self.class
|
123
|
+
elsif embedded?
|
90
124
|
_parent.send(association_name)
|
91
125
|
else
|
92
126
|
self.class
|
93
|
-
end
|
94
|
-
where(slug_name => slug).
|
95
|
-
reject { |doc| doc.id == self.id }.
|
96
|
-
empty?
|
127
|
+
end
|
97
128
|
end
|
98
129
|
end
|
99
130
|
end
|
data/lib/mongoid/slug/version.rb
CHANGED
data/spec/models/author.rb
CHANGED
@@ -3,6 +3,9 @@ class Author
|
|
3
3
|
include Mongoid::Slug
|
4
4
|
field :first_name
|
5
5
|
field :last_name
|
6
|
-
slug :first_name, :last_name
|
6
|
+
slug :first_name, :last_name, :scope => :book, :index => true
|
7
7
|
referenced_in :book
|
8
|
+
references_many :characters,
|
9
|
+
:class_name => 'Person',
|
10
|
+
:foreign_key => :author_id
|
8
11
|
end
|
data/spec/models/book.rb
CHANGED
data/spec/models/person.rb
CHANGED
@@ -2,6 +2,7 @@ class Person
|
|
2
2
|
include Mongoid::Document
|
3
3
|
include Mongoid::Slug
|
4
4
|
field :name
|
5
|
-
slug :name, :as => :permalink, :permanent => true
|
5
|
+
slug :name, :as => :permalink, :permanent => true, :scope => :author
|
6
6
|
embeds_many :relationships
|
7
|
+
referenced_in :author, :inverse_of => :characters
|
7
8
|
end
|
data/spec/mongoid/slug_spec.rb
CHANGED
@@ -182,6 +182,47 @@ module Mongoid
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
185
|
+
context "when slug is scoped by a reference association" do
|
186
|
+
let(:author) do
|
187
|
+
book.authors.create(:first_name => "Gilles", :last_name => "Deleuze")
|
188
|
+
end
|
189
|
+
|
190
|
+
it "scopes by parent object" do
|
191
|
+
book2 = Book.create(:title => "Anti Oedipus")
|
192
|
+
dup = book2.authors.create(
|
193
|
+
:first_name => author.first_name,
|
194
|
+
:last_name => author.last_name
|
195
|
+
)
|
196
|
+
dup.to_param.should eql author.to_param
|
197
|
+
end
|
198
|
+
|
199
|
+
it "generates a unique slug by appending a counter to duplicate text" do
|
200
|
+
dup = book.authors.create(
|
201
|
+
:first_name => author.first_name,
|
202
|
+
:last_name => author.last_name)
|
203
|
+
dup.to_param.should eql 'gilles-deleuze-1'
|
204
|
+
end
|
205
|
+
|
206
|
+
context "with an irregular association name" do
|
207
|
+
let(:character) do
|
208
|
+
# well we've got to make up something... :-)
|
209
|
+
author.characters.create(:name => "Oedipus")
|
210
|
+
end
|
211
|
+
|
212
|
+
let!(:author2) do
|
213
|
+
Author.create(
|
214
|
+
:first_name => "Sophocles",
|
215
|
+
:last_name => "son of Sophilos"
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
it "scopes by parent object provided that inverse_of is specified" do
|
220
|
+
dup = author2.characters.create(:name => character.name)
|
221
|
+
dup.to_param.should eql character.to_param
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
185
226
|
it "works with non-Latin characters" do
|
186
227
|
book.title = "Капитал"
|
187
228
|
book.save
|
@@ -195,5 +236,52 @@ module Mongoid
|
|
195
236
|
book.save
|
196
237
|
book.to_param.should eql 'zhong-wen'
|
197
238
|
end
|
239
|
+
|
240
|
+
it "deprecates the :scoped option" do
|
241
|
+
ActiveSupport::Deprecation.should_receive(:warn)
|
242
|
+
class Oldie
|
243
|
+
include Mongoid::Document
|
244
|
+
include Mongoid::Slug
|
245
|
+
field :name
|
246
|
+
slug :name, :scoped => true
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context "when :index is set to true" do
|
251
|
+
before do
|
252
|
+
Book.collection.drop_indexes
|
253
|
+
Author.collection.drop_indexes
|
254
|
+
end
|
255
|
+
|
256
|
+
it "indexes slug in top-level objects" do
|
257
|
+
Book.create_indexes
|
258
|
+
Book.collection.index_information.should have_key "slug_1"
|
259
|
+
end
|
260
|
+
|
261
|
+
context "when slug is scoped by a reference association" do
|
262
|
+
it "creates a non-unique index" do
|
263
|
+
Author.create_indexes
|
264
|
+
Author.index_information["slug_1"]["unique"].should be_false
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context "when slug is not scoped by a reference association" do
|
269
|
+
it "creates a unique index" do
|
270
|
+
Book.create_indexes
|
271
|
+
Book.index_information["slug_1"]["unique"].should be_true
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
it "does not index slug in embedded objects" do
|
276
|
+
pending "Would such an option even make sense?"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context "when :index is not set" do
|
281
|
+
it "does not index slug" do
|
282
|
+
Person.create_indexes
|
283
|
+
Person.collection.index_information.should_not have_key "permalink_1"
|
284
|
+
end
|
285
|
+
end
|
198
286
|
end
|
199
287
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 5
|
8
|
-
-
|
9
|
-
version: 0.5.
|
8
|
+
- 1
|
9
|
+
version: 0.5.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Paper Cavalier
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-12-
|
17
|
+
date: 2010-12-30 00:00:00 -03:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -94,6 +94,21 @@ dependencies:
|
|
94
94
|
version: 2.3.0
|
95
95
|
type: :development
|
96
96
|
version_requirements: *id005
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: ruby-debug19
|
99
|
+
prerelease: false
|
100
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ~>
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
- 11
|
108
|
+
- 0
|
109
|
+
version: 0.11.0
|
110
|
+
type: :development
|
111
|
+
version_requirements: *id006
|
97
112
|
description: Mongoid Slug generates a URL slug or permalink based on one or more fields in a Mongoid model.
|
98
113
|
email:
|
99
114
|
- code@papercavalier.com
|