vidibus-permalink 0.0.1
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/.bundle/config +2 -0
- data/.document +5 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +120 -0
- data/LICENSE +20 -0
- data/README.rdoc +37 -0
- data/Rakefile +40 -0
- data/VERSION +1 -0
- data/app/models/permalink.rb +161 -0
- data/lib/vidibus/permalink/dispatcher.rb +83 -0
- data/lib/vidibus/permalink/mongoid.rb +71 -0
- data/lib/vidibus/permalink.rb +2 -0
- data/lib/vidibus-permalink.rb +14 -0
- data/spec/models.rb +20 -0
- data/spec/permalink_spec.rb +223 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/vidibus/permalink/dispatcher_spec.rb +122 -0
- data/spec/vidibus/permalink/mongoid_spec.rb +147 -0
- data/vidibus-permalink.gemspec +80 -0
- metadata +167 -0
data/.bundle/config
ADDED
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gem "rails", "~> 3.0.0"
|
4
|
+
gem "mongoid", "~> 2.0.0.beta.20"
|
5
|
+
gem "vidibus-core_extensions"
|
6
|
+
gem "vidibus-uuid"
|
7
|
+
gem "vidibus-words"
|
8
|
+
|
9
|
+
# Development dependecies
|
10
|
+
gem "jeweler"
|
11
|
+
gem "rake"
|
12
|
+
gem "rspec", "~> 2.0.0.beta.20"
|
13
|
+
gem "rr"
|
14
|
+
gem "relevance-rcov"
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
abstract (1.0.0)
|
5
|
+
actionmailer (3.0.1)
|
6
|
+
actionpack (= 3.0.1)
|
7
|
+
mail (~> 2.2.5)
|
8
|
+
actionpack (3.0.1)
|
9
|
+
activemodel (= 3.0.1)
|
10
|
+
activesupport (= 3.0.1)
|
11
|
+
builder (~> 2.1.2)
|
12
|
+
erubis (~> 2.6.6)
|
13
|
+
i18n (~> 0.4.1)
|
14
|
+
rack (~> 1.2.1)
|
15
|
+
rack-mount (~> 0.6.12)
|
16
|
+
rack-test (~> 0.5.4)
|
17
|
+
tzinfo (~> 0.3.23)
|
18
|
+
activemodel (3.0.1)
|
19
|
+
activesupport (= 3.0.1)
|
20
|
+
builder (~> 2.1.2)
|
21
|
+
i18n (~> 0.4.1)
|
22
|
+
activerecord (3.0.1)
|
23
|
+
activemodel (= 3.0.1)
|
24
|
+
activesupport (= 3.0.1)
|
25
|
+
arel (~> 1.0.0)
|
26
|
+
tzinfo (~> 0.3.23)
|
27
|
+
activeresource (3.0.1)
|
28
|
+
activemodel (= 3.0.1)
|
29
|
+
activesupport (= 3.0.1)
|
30
|
+
activesupport (3.0.1)
|
31
|
+
arel (1.0.1)
|
32
|
+
activesupport (~> 3.0.0)
|
33
|
+
bson (1.1.2)
|
34
|
+
builder (2.1.2)
|
35
|
+
diff-lcs (1.1.2)
|
36
|
+
erubis (2.6.6)
|
37
|
+
abstract (>= 1.0.0)
|
38
|
+
gemcutter (0.6.1)
|
39
|
+
git (1.2.5)
|
40
|
+
i18n (0.4.2)
|
41
|
+
jeweler (1.4.0)
|
42
|
+
gemcutter (>= 0.1.0)
|
43
|
+
git (>= 1.2.5)
|
44
|
+
rubyforge (>= 2.0.0)
|
45
|
+
json_pure (1.4.6)
|
46
|
+
macaddr (1.0.0)
|
47
|
+
mail (2.2.9)
|
48
|
+
activesupport (>= 2.3.6)
|
49
|
+
i18n (~> 0.4.1)
|
50
|
+
mime-types (~> 1.16)
|
51
|
+
treetop (~> 1.4.8)
|
52
|
+
mime-types (1.16)
|
53
|
+
mongo (1.1.2)
|
54
|
+
bson (>= 1.1.1)
|
55
|
+
mongoid (2.0.0.beta.20)
|
56
|
+
activemodel (~> 3.0)
|
57
|
+
mongo (~> 1.1)
|
58
|
+
tzinfo (~> 0.3.22)
|
59
|
+
will_paginate (~> 3.0.pre)
|
60
|
+
polyglot (0.3.1)
|
61
|
+
rack (1.2.1)
|
62
|
+
rack-mount (0.6.13)
|
63
|
+
rack (>= 1.0.0)
|
64
|
+
rack-test (0.5.6)
|
65
|
+
rack (>= 1.0)
|
66
|
+
rails (3.0.1)
|
67
|
+
actionmailer (= 3.0.1)
|
68
|
+
actionpack (= 3.0.1)
|
69
|
+
activerecord (= 3.0.1)
|
70
|
+
activeresource (= 3.0.1)
|
71
|
+
activesupport (= 3.0.1)
|
72
|
+
bundler (~> 1.0.0)
|
73
|
+
railties (= 3.0.1)
|
74
|
+
railties (3.0.1)
|
75
|
+
actionpack (= 3.0.1)
|
76
|
+
activesupport (= 3.0.1)
|
77
|
+
rake (>= 0.8.4)
|
78
|
+
thor (~> 0.14.0)
|
79
|
+
rake (0.8.7)
|
80
|
+
relevance-rcov (0.9.2.1)
|
81
|
+
rr (1.0.2)
|
82
|
+
rspec (2.0.1)
|
83
|
+
rspec-core (~> 2.0.1)
|
84
|
+
rspec-expectations (~> 2.0.1)
|
85
|
+
rspec-mocks (~> 2.0.1)
|
86
|
+
rspec-core (2.0.1)
|
87
|
+
rspec-expectations (2.0.1)
|
88
|
+
diff-lcs (>= 1.1.2)
|
89
|
+
rspec-mocks (2.0.1)
|
90
|
+
rspec-core (~> 2.0.1)
|
91
|
+
rspec-expectations (~> 2.0.1)
|
92
|
+
rubyforge (2.0.4)
|
93
|
+
json_pure (>= 1.1.7)
|
94
|
+
thor (0.14.4)
|
95
|
+
treetop (1.4.8)
|
96
|
+
polyglot (>= 0.3.1)
|
97
|
+
tzinfo (0.3.23)
|
98
|
+
uuid (2.3.1)
|
99
|
+
macaddr (~> 1.0)
|
100
|
+
vidibus-core_extensions (0.3.11)
|
101
|
+
vidibus-uuid (0.3.8)
|
102
|
+
mongoid (~> 2.0.0.beta.20)
|
103
|
+
uuid (~> 2.3.1)
|
104
|
+
vidibus-words (0.0.0)
|
105
|
+
will_paginate (3.0.pre2)
|
106
|
+
|
107
|
+
PLATFORMS
|
108
|
+
ruby
|
109
|
+
|
110
|
+
DEPENDENCIES
|
111
|
+
jeweler
|
112
|
+
mongoid (~> 2.0.0.beta.20)
|
113
|
+
rails (~> 3.0.0)
|
114
|
+
rake
|
115
|
+
relevance-rcov
|
116
|
+
rr
|
117
|
+
rspec (~> 2.0.0.beta.20)
|
118
|
+
vidibus-core_extensions
|
119
|
+
vidibus-uuid
|
120
|
+
vidibus-words
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Andre Pankratz
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
= vidibus-permalink
|
2
|
+
|
3
|
+
This gem allows changeable permalinks. That's an oxymoron, but it's really useful from a SEO perspective.
|
4
|
+
|
5
|
+
It is part of the open source SOA framework Vidibus: http://vidibus.org
|
6
|
+
|
7
|
+
|
8
|
+
== Installation
|
9
|
+
|
10
|
+
Add the dependency to the Gemfile of your application:
|
11
|
+
|
12
|
+
gem "vidibus-permalink"
|
13
|
+
|
14
|
+
Then call bundle install on your console.
|
15
|
+
|
16
|
+
|
17
|
+
== Usage
|
18
|
+
|
19
|
+
TODO: describe
|
20
|
+
|
21
|
+
|
22
|
+
== TODO
|
23
|
+
|
24
|
+
* Add controller extension for automatic dispatching
|
25
|
+
* Limit length of permalinks
|
26
|
+
|
27
|
+
|
28
|
+
== Ideas (for a separate gem)
|
29
|
+
|
30
|
+
* Catch 404s and store invalid routes.
|
31
|
+
* Make invalid routes assignable from a web interface.
|
32
|
+
* Try to suggest a matching Linkable by valid parts of the request path.
|
33
|
+
|
34
|
+
|
35
|
+
== Copyright
|
36
|
+
|
37
|
+
Copyright (c) 2010 Andre Pankratz. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake"
|
3
|
+
require "rake/rdoctask"
|
4
|
+
require "rspec"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
|
7
|
+
begin
|
8
|
+
require "jeweler"
|
9
|
+
Jeweler::Tasks.new do |gem|
|
10
|
+
gem.name = "vidibus-permalink"
|
11
|
+
gem.summary = %Q{Permalink handling}
|
12
|
+
gem.description = %Q{Allows changeable permalinks (good for SEO).}
|
13
|
+
gem.email = "andre@vidibus.com"
|
14
|
+
gem.homepage = "http://github.com/vidibus/vidibus-permalink"
|
15
|
+
gem.authors = ["Andre Pankratz"]
|
16
|
+
gem.add_dependency "rails", "~> 3.0.0"
|
17
|
+
gem.add_dependency "mongoid", "~> 2.0.0.beta.20"
|
18
|
+
gem.add_dependency "vidibus-core_extensions"
|
19
|
+
gem.add_dependency "vidibus-uuid"
|
20
|
+
gem.add_dependency "vidibus-words"
|
21
|
+
end
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
Rspec::Core::RakeTask.new(:rcov) do |t|
|
28
|
+
t.pattern = "spec/**/*_spec.rb"
|
29
|
+
t.rcov = true
|
30
|
+
t.rcov_opts = ["--exclude", "^spec,/gems/"]
|
31
|
+
end
|
32
|
+
|
33
|
+
Rake::RDocTask.new do |rdoc|
|
34
|
+
version = File.exist?("VERSION") ? File.read("VERSION") : ""
|
35
|
+
rdoc.rdoc_dir = "rdoc"
|
36
|
+
rdoc.title = "vidibus-permalink #{version}"
|
37
|
+
rdoc.rdoc_files.include("README*")
|
38
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
39
|
+
rdoc.options << "--charset=utf-8"
|
40
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,161 @@
|
|
1
|
+
class Permalink
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Timestamps
|
4
|
+
|
5
|
+
class UuidRequiredError < StandardError; end
|
6
|
+
|
7
|
+
field :value
|
8
|
+
field :linkable_class
|
9
|
+
field :linkable_uuid
|
10
|
+
field :_current, :type => Boolean, :default => true
|
11
|
+
|
12
|
+
before_save :set_current
|
13
|
+
after_destroy :set_last_current, :if => :current?
|
14
|
+
|
15
|
+
validates :linkable_uuid, :uuid => true
|
16
|
+
validates :value, :linkable_class, :presence => true
|
17
|
+
|
18
|
+
index :value
|
19
|
+
|
20
|
+
# Sets object as linkable.
|
21
|
+
def linkable=(obj)
|
22
|
+
@linkable = nil
|
23
|
+
self.linkable_class = obj.class.to_s
|
24
|
+
if uuid = obj.try!(:uuid)
|
25
|
+
self.linkable_uuid = uuid
|
26
|
+
else
|
27
|
+
raise UuidRequiredError.new("The linkable object must respond to #uuid. The gem vidibus-uuid will help you.")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the linkable object.
|
32
|
+
def linkable
|
33
|
+
@linkable ||= begin
|
34
|
+
return unless linkable_class and linkable_uuid
|
35
|
+
linkable_class.constantize.where(:uuid => linkable_uuid).first
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Assigns given string as value.
|
40
|
+
# Sanitizes and increments string, if necessary.
|
41
|
+
def value=(string)
|
42
|
+
unless string == value
|
43
|
+
string = sanitize(string)
|
44
|
+
unless string == value
|
45
|
+
string = increment(string)
|
46
|
+
self.write_attribute(:value, string)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
string
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns true if this permalink is the current one
|
53
|
+
# of the assigned linkable.
|
54
|
+
def current?
|
55
|
+
@is_current ||= !!_current
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns the current permalink of the assigned linkable.
|
59
|
+
def current
|
60
|
+
@current ||= begin
|
61
|
+
if current?
|
62
|
+
self
|
63
|
+
else
|
64
|
+
Permalink.where(:linkable_uuid => linkable_uuid, :_current => true).first
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class << self
|
70
|
+
|
71
|
+
# Scope method for finding Permalinks for given object.
|
72
|
+
def for_linkable(object)
|
73
|
+
where(:linkable_uuid => object.uuid)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Scope method for finding Permalinks for given value.
|
77
|
+
# The value will be sanitized.
|
78
|
+
def for_value(value)
|
79
|
+
where(:value => sanitize(value))
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns a dispatcher object for given path.
|
83
|
+
def dispatch(path)
|
84
|
+
Vidibus::Permalink::Dispatcher.new(path)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
|
90
|
+
# Removes stopwords and turns string into a permalink-formatted one.
|
91
|
+
# However, if the stopwords-free value is blank or it already exists
|
92
|
+
# in the database, the full value will be used.
|
93
|
+
def sanitize(string)
|
94
|
+
return if string.blank?
|
95
|
+
clean = Permalink.remove_stopwords(string)
|
96
|
+
unless clean.blank? or clean == string
|
97
|
+
clean = clean.permalink
|
98
|
+
sanitized = clean unless existing(clean).any?
|
99
|
+
end
|
100
|
+
sanitized || string.permalink
|
101
|
+
end
|
102
|
+
|
103
|
+
# Sanitize string: Remove stopwords and format as permalink.
|
104
|
+
# See Vidibus::CoreExtensions::String for details.
|
105
|
+
def self.sanitize(string)
|
106
|
+
return if string.blank?
|
107
|
+
remove_stopwords(string).permalink
|
108
|
+
end
|
109
|
+
|
110
|
+
# Tries to remove stopwords from string.
|
111
|
+
# If the resulting string is blank, the original one will be returned.
|
112
|
+
# See Vidibus::Words for details.
|
113
|
+
def self.remove_stopwords(string)
|
114
|
+
words = Vidibus::Words.new(string)
|
115
|
+
clean = words.keywords(10).join(" ")
|
116
|
+
clean.blank? ? string : clean
|
117
|
+
end
|
118
|
+
|
119
|
+
# Appends next available number to string if it's already in use.
|
120
|
+
def increment(string)
|
121
|
+
_existing = existing(string)
|
122
|
+
return string unless _existing.any?
|
123
|
+
number = 1
|
124
|
+
while true
|
125
|
+
number += 1
|
126
|
+
desired = "#{string}-#{number}"
|
127
|
+
unless _existing.detect {|e| e.value == desired}
|
128
|
+
return desired
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Finds existing permalinks with current value.
|
134
|
+
def existing(string)
|
135
|
+
@existing ||= {}
|
136
|
+
@existing[string] ||= Permalink.where(:value => /^#{string}(-\d+)?$/).excludes(:_id => id).to_a
|
137
|
+
end
|
138
|
+
|
139
|
+
# Sets this permalink as the current one and unsets all others.
|
140
|
+
def set_current
|
141
|
+
unset_other_current
|
142
|
+
self._current = true
|
143
|
+
end
|
144
|
+
|
145
|
+
# Sets _current to false on all permalinks of the assigned linkable.
|
146
|
+
def unset_other_current
|
147
|
+
return unless linkable
|
148
|
+
collection.update(
|
149
|
+
{:linkable_uuid => linkable_uuid, :_id => {"$ne" => _id}},
|
150
|
+
{"$set" => {:_current => false}},
|
151
|
+
{:multi => true}
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Sets the lastly updated permalink of the assigned linkable as current one.
|
156
|
+
def set_last_current
|
157
|
+
if last = Permalink.where(:linkable_uuid => linkable_uuid).order_by(:updated_at.desc).limit(1).first
|
158
|
+
last.update_attributes!(:_current => true)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Vidibus
|
2
|
+
module Permalink
|
3
|
+
class Dispatcher
|
4
|
+
|
5
|
+
class PathError < StandardError; end
|
6
|
+
|
7
|
+
# Initialize a new Dispatcher instance.
|
8
|
+
# Provide an absolute +path+ to be dispatched.
|
9
|
+
def initialize(path)
|
10
|
+
unless path.match(/^\//)
|
11
|
+
raise PathError, "Path must be absolute."
|
12
|
+
end
|
13
|
+
@path = path
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the path to dispatch.
|
17
|
+
def path
|
18
|
+
@path
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns parts of the path.
|
22
|
+
def parts
|
23
|
+
@parts ||= path.split("/").reject{|p| p == ""}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns permalink objects matching the parts.
|
27
|
+
def objects
|
28
|
+
@objects ||= resolve_path
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns true if all parts could be resolved.
|
32
|
+
def found?
|
33
|
+
@is_found ||= begin
|
34
|
+
!objects.include?(nil)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns true if any part does not reflect
|
39
|
+
# the current permalink of the underlying linkable.
|
40
|
+
def redirect?
|
41
|
+
@is_redirect ||= begin
|
42
|
+
return unless found?
|
43
|
+
redirectables.any?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the path to redirect to, if any.
|
48
|
+
def redirect_path
|
49
|
+
@redirect_path ||= begin
|
50
|
+
return unless redirect?
|
51
|
+
"/" << current_parts.join("/")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# TODO: Allow scopes
|
58
|
+
def resolve_path
|
59
|
+
results = ::Permalink.any_in(:value => parts)
|
60
|
+
links = Array.new(parts.length)
|
61
|
+
done = {}
|
62
|
+
for result in results
|
63
|
+
if i = parts.index(result.value)
|
64
|
+
key = "#{result.linkable_class}##{result.linkable_uuid}"
|
65
|
+
next if done[key]
|
66
|
+
links[i] = result
|
67
|
+
done[key] = true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
links
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns an array containing the current permalinks of all objects.
|
74
|
+
def current_parts
|
75
|
+
objects.map {|o| o.current.value}
|
76
|
+
end
|
77
|
+
|
78
|
+
def redirectables
|
79
|
+
objects.select {|o| !o.current?}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Vidibus
|
2
|
+
module Permalink
|
3
|
+
module Mongoid
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class PermalinkConfigurationError < StandardError; end
|
7
|
+
|
8
|
+
included do
|
9
|
+
field :permalink
|
10
|
+
before_validation :set_permalink
|
11
|
+
validates :permalink, :presence => true
|
12
|
+
after_save :store_permalink_object
|
13
|
+
after_destroy :destroy_permalink_objects
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
# Sets permalink attributes.
|
19
|
+
# Usage:
|
20
|
+
# permalink :some, :fields
|
21
|
+
def permalink(*args)
|
22
|
+
class_eval <<-EOS
|
23
|
+
def permalink_attributes
|
24
|
+
#{args.inspect}
|
25
|
+
end
|
26
|
+
EOS
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the current permalink object.
|
31
|
+
def permalink_object
|
32
|
+
@permalink_object || ::Permalink.for_linkable(self).where(:_current => true).first
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns all permalink objects ordered by time of update.
|
36
|
+
def permalink_objects
|
37
|
+
::Permalink.for_linkable(self).asc(:updated_at)
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# Initializes a new permalink object and sets permalink attribute.
|
43
|
+
def set_permalink
|
44
|
+
if attributes = try!(:permalink_attributes)
|
45
|
+
changed = false
|
46
|
+
values = []
|
47
|
+
for a in attributes
|
48
|
+
changed = send("#{a}_changed?") unless changed == true
|
49
|
+
values << send(a)
|
50
|
+
end
|
51
|
+
return unless permalink.blank? or changed
|
52
|
+
value = values.join(" ")
|
53
|
+
@permalink_object = ::Permalink.for_linkable(self).for_value(value).first
|
54
|
+
@permalink_object ||= ::Permalink.new(:value => value, :linkable => self)
|
55
|
+
self.permalink = @permalink_object.value
|
56
|
+
else
|
57
|
+
raise PermalinkConfigurationError.new("Permalink attributes have not been assigned!")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Stores current new permalink object or updates an existing one that matches.
|
62
|
+
def store_permalink_object
|
63
|
+
@permalink_object.save! if @permalink_object
|
64
|
+
end
|
65
|
+
|
66
|
+
def destroy_permalink_objects
|
67
|
+
::Permalink.delete_all(:conditions => {:linkable_uuid => uuid})
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "rails"
|
2
|
+
require "mongoid"
|
3
|
+
require "vidibus-core_extensions"
|
4
|
+
require "vidibus-uuid"
|
5
|
+
require "vidibus-words"
|
6
|
+
|
7
|
+
$:.unshift(File.join(File.dirname(__FILE__), "vidibus"))
|
8
|
+
require "permalink"
|
9
|
+
|
10
|
+
if defined?(Rails)
|
11
|
+
module Vidibus::Permalink
|
12
|
+
class Engine < ::Rails::Engine; end
|
13
|
+
end
|
14
|
+
end
|
data/spec/models.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "vidibus-uuid"
|
2
|
+
|
3
|
+
class Asset
|
4
|
+
include Mongoid::Document
|
5
|
+
include Vidibus::Uuid::Mongoid
|
6
|
+
field :label
|
7
|
+
end
|
8
|
+
|
9
|
+
class Category
|
10
|
+
include Mongoid::Document
|
11
|
+
include Vidibus::Uuid::Mongoid
|
12
|
+
field :label
|
13
|
+
end
|
14
|
+
|
15
|
+
# class Article
|
16
|
+
# include Mongoid::Document
|
17
|
+
# field :label
|
18
|
+
# field :date, :format => Date
|
19
|
+
# #permalink :label, :date
|
20
|
+
# end
|