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 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(:first => "Félix", :last_name => "Guattari")
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
- if embedded?
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
@@ -1,5 +1,5 @@
1
1
  module Mongoid #:nodoc:
2
2
  module Slug
3
- VERSION = "0.5.0"
3
+ VERSION = "0.5.1"
4
4
  end
5
5
  end
@@ -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
@@ -2,7 +2,7 @@ class Book
2
2
  include Mongoid::Document
3
3
  include Mongoid::Slug
4
4
  field :title
5
- slug :title
5
+ slug :title, :index => true
6
6
  embeds_many :subjects
7
7
  references_many :authors
8
8
  end
@@ -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
@@ -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
- - 0
9
- version: 0.5.0
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-28 00:00:00 -03:00
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