leifcr-mm-sluggable 0.2.5
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.
- data/Gemfile +19 -0
- data/LICENSE +21 -0
- data/README.rdoc +75 -0
- data/Rakefile +9 -0
- data/lib/mm-sluggable.rb +83 -0
- data/lib/sluggable/version.rb +3 -0
- metadata +83 -0
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source :rubygems
|
2
|
+
gem 'rake'
|
3
|
+
gem 'bson_ext', '>= 1.6.4'
|
4
|
+
gem 'multi_json', '>= 1.3.6'
|
5
|
+
|
6
|
+
group :test do
|
7
|
+
# gem 'jnunemaker-matchy', '>= 0.4', :require => 'matchy'
|
8
|
+
# gem 'shoulda', '>= 3.1.1'
|
9
|
+
# gem 'mocha', '>= 0.12.3'
|
10
|
+
gem 'rspec'
|
11
|
+
gem 'database_cleaner', '>= 0.8.0'
|
12
|
+
end
|
13
|
+
|
14
|
+
group :development do
|
15
|
+
gem "wirble"
|
16
|
+
gem "hirb"
|
17
|
+
gem "awesome_print"
|
18
|
+
end
|
19
|
+
gemspec
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2010 Richard Livsey
|
2
|
+
Copyright (c) 2012 Leif Ringstad
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
= MongoMapper::Plugins::Sluggable
|
2
|
+
|
3
|
+
Add slugs to your fields. And use it for URLS...
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
Either load it into all models, or individual models:
|
8
|
+
|
9
|
+
Add to all models
|
10
|
+
#initializers/mongo.rb
|
11
|
+
MongoMapper::Document.plugin(MongoMapper::Plugins::Sluggable)
|
12
|
+
|
13
|
+
Add to a specific model
|
14
|
+
#app/models/my_model.rb
|
15
|
+
plugin MongoMapper::Plugins::Sluggable
|
16
|
+
|
17
|
+
Then call sluggable to configure it
|
18
|
+
sluggable :title, :scope => :account_id
|
19
|
+
|
20
|
+
NOTE: The slugs will always be updated if you change the field it creates
|
21
|
+
the slugs from. see options to change behaviour
|
22
|
+
|
23
|
+
Free slugs will be reused
|
24
|
+
Example: you have my-title-1 and my-title-3 creating a new slug will generate my-title-2
|
25
|
+
|
26
|
+
Why always change slugs? Feels better to have same slug as title...
|
27
|
+
|
28
|
+
== Improve performance on your models
|
29
|
+
|
30
|
+
This is important to get fast queries! (you will regret if you don't add it...)
|
31
|
+
|
32
|
+
Read up on indexes here:
|
33
|
+
https://github.com/jnunemaker/mongomapper/issues/337
|
34
|
+
|
35
|
+
Easiest is to add db/indexes.rb to your app, then add this to that file:
|
36
|
+
# db/indexes.rb
|
37
|
+
MyModel.ensure_index(:slug_key)
|
38
|
+
|
39
|
+
== Options
|
40
|
+
|
41
|
+
Available options are:
|
42
|
+
|
43
|
+
* :scope - scope to a specific field (default - nil)
|
44
|
+
* :key - what the slug key is called (default - :slug) - NOTE, don't change this one
|
45
|
+
* :method - what method to call on the field to sluggify it (default - :parameterize)
|
46
|
+
* :callback - when to trigger the slugging (default - :before_validation_on_create)
|
47
|
+
* :always_update - Always update the slug on update/save/create etc.
|
48
|
+
|
49
|
+
Eg.
|
50
|
+
|
51
|
+
sluggable :title, :scope => :account_id, :key => :title_slug, :method => :to_url, :index => false
|
52
|
+
|
53
|
+
This will slug the title to the title_slug key, scoped to the account, will use String#to_url to slug it and won't add an index to the key
|
54
|
+
|
55
|
+
== Versioning
|
56
|
+
|
57
|
+
If an item with the same slug exists, it will add a version number to the slug.
|
58
|
+
|
59
|
+
IE assuming we already have an item with the slug of "monkey", the slug will be generated as "monkey-1"
|
60
|
+
|
61
|
+
== Note on Patches/Pull Requests
|
62
|
+
* Fork the project.
|
63
|
+
* Make your feature addition or bug fix.
|
64
|
+
* Add tests for it.
|
65
|
+
|
66
|
+
== Install
|
67
|
+
Bundler: (You are most likely using bundler in your app...)
|
68
|
+
gem 'mm-sluggable', :git => 'http://github.com/luuf/mm-sluggable.git'
|
69
|
+
|
70
|
+
== Thanks
|
71
|
+
* Richard Livsey for creating the original mm-sluggable
|
72
|
+
* John Nunemaker, Brandon Keepers & Others for MongoMapper
|
73
|
+
|
74
|
+
== Copyright
|
75
|
+
See LICENSE for details.
|
data/Rakefile
ADDED
data/lib/mm-sluggable.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'mongo_mapper'
|
2
|
+
|
3
|
+
module MongoMapper
|
4
|
+
module Plugins
|
5
|
+
module Sluggable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def sluggable(to_slug = :title, options = {})
|
10
|
+
class_attribute :slug_options
|
11
|
+
|
12
|
+
self.slug_options = {
|
13
|
+
:to_slug => to_slug,
|
14
|
+
:key => :slug,
|
15
|
+
:method => :parameterize,
|
16
|
+
:scope => nil,
|
17
|
+
:max_length => 256,
|
18
|
+
:always_update => true, # allow always updating slug...
|
19
|
+
:callback => :before_validation,
|
20
|
+
:callback_on => nil,
|
21
|
+
}.merge(options)
|
22
|
+
key slug_options[:key], String
|
23
|
+
|
24
|
+
#before_validation :set_slug
|
25
|
+
self.send(slug_options[:callback], :set_slug, {:on => slug_options[:callback_on]}) if slug_options[:callback] && slug_options[:callback_on]
|
26
|
+
self.send(slug_options[:callback], :set_slug) if slug_options[:callback] && slug_options[:callback_on].nil?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_slug
|
31
|
+
options = self.class.slug_options
|
32
|
+
|
33
|
+
if options[:always_update] == false
|
34
|
+
return unless self.send(options[:key]).blank?
|
35
|
+
end
|
36
|
+
|
37
|
+
to_slug = self[options[:to_slug]]
|
38
|
+
return if to_slug.blank?
|
39
|
+
|
40
|
+
# previous_slug = self[:key]
|
41
|
+
|
42
|
+
the_slug = raw_slug = to_slug.send(options[:method]).to_s[0...options[:max_length]]
|
43
|
+
|
44
|
+
# no need to set, so return
|
45
|
+
return if (self.send(options[:key]) == the_slug)
|
46
|
+
# also do a regexp check,
|
47
|
+
# verify if the previous slug is "almost" the same as we want without digits/extras
|
48
|
+
return if (/(#{the_slug}-\d+)/.match(self.send(options[:key])) != nil)
|
49
|
+
|
50
|
+
conds = {}
|
51
|
+
conds[options[:key]] = the_slug
|
52
|
+
conds[options[:scope]] = self.send(options[:scope]) if options[:scope]
|
53
|
+
|
54
|
+
# first see if there is a equal slug
|
55
|
+
used_slugs = self.class.where(conds)
|
56
|
+
if (used_slugs.count > 0)
|
57
|
+
last_digit = 0 # zero for last one...
|
58
|
+
# if we are updating, check if the current slug is same as the one we want
|
59
|
+
conds[options[:key]] = /(#{the_slug}-\d+)/
|
60
|
+
used_slugs = self.class.where(conds).sort(options[:key].asc)
|
61
|
+
new_slug_set = false
|
62
|
+
used_slugs.each do |used_slug|
|
63
|
+
# get the last digit through regex
|
64
|
+
next_digit = used_slug.send(options[:key])[/(\d+)$/]
|
65
|
+
if (!next_digit.nil?)
|
66
|
+
# catch any numbers that are in between and free
|
67
|
+
if ((next_digit.to_i - last_digit.to_i) > 1)
|
68
|
+
the_slug = "#{raw_slug}-#{last_digit+1}"
|
69
|
+
new_slug_set = true
|
70
|
+
break # set a new slug, so all is good
|
71
|
+
end
|
72
|
+
last_digit = next_digit.to_i
|
73
|
+
# puts last_digit.inspect
|
74
|
+
end
|
75
|
+
end
|
76
|
+
the_slug = "#{raw_slug}-#{last_digit+1}" if new_slug_set == false
|
77
|
+
end
|
78
|
+
|
79
|
+
self.send(:"#{options[:key]}=", the_slug)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: leifcr-mm-sluggable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.5
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Leif Ringstad
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mongo_mapper
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.12.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.12.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description:
|
47
|
+
email:
|
48
|
+
- leifcr@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- lib/mm-sluggable.rb
|
54
|
+
- lib/sluggable/version.rb
|
55
|
+
- Gemfile
|
56
|
+
- Rakefile
|
57
|
+
- LICENSE
|
58
|
+
- README.rdoc
|
59
|
+
homepage: http://github.com/leifcr/mm-sluggable
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.24
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: MongoMapper Plugin to store a slugged version of of a field.
|
83
|
+
test_files: []
|