friendly_id 2.2.7 → 2.3.0
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/Changelog.md +225 -0
- data/Contributors.md +28 -0
- data/Guide.md +509 -0
- data/LICENSE +1 -1
- data/README.md +76 -0
- data/Rakefile +48 -15
- data/extras/bench.rb +59 -0
- data/extras/extras.rb +31 -0
- data/extras/prof.rb +14 -0
- data/extras/template-gem.rb +1 -1
- data/extras/template-plugin.rb +1 -1
- data/generators/friendly_id/friendly_id_generator.rb +1 -1
- data/generators/friendly_id/templates/create_slugs.rb +2 -2
- data/lib/friendly_id.rb +54 -63
- data/lib/friendly_id/active_record2.rb +47 -0
- data/lib/friendly_id/active_record2/configuration.rb +66 -0
- data/lib/friendly_id/active_record2/finders.rb +140 -0
- data/lib/friendly_id/active_record2/simple_model.rb +162 -0
- data/lib/friendly_id/active_record2/slug.rb +111 -0
- data/lib/friendly_id/active_record2/slugged_model.rb +317 -0
- data/lib/friendly_id/active_record2/tasks.rb +66 -0
- data/lib/friendly_id/active_record2/tasks/friendly_id.rake +19 -0
- data/lib/friendly_id/configuration.rb +132 -0
- data/lib/friendly_id/finders.rb +106 -0
- data/lib/friendly_id/slug_string.rb +292 -0
- data/lib/friendly_id/slugged.rb +91 -0
- data/lib/friendly_id/status.rb +35 -0
- data/lib/friendly_id/test.rb +168 -0
- data/lib/friendly_id/version.rb +5 -5
- data/rails/init.rb +2 -0
- data/test/active_record2/basic_slugged_model_test.rb +14 -0
- data/test/active_record2/cached_slug_test.rb +61 -0
- data/test/active_record2/core.rb +93 -0
- data/test/active_record2/custom_normalizer_test.rb +20 -0
- data/test/active_record2/custom_table_name_test.rb +22 -0
- data/test/active_record2/scoped_model_test.rb +111 -0
- data/test/active_record2/simple_test.rb +59 -0
- data/test/active_record2/slug_test.rb +34 -0
- data/test/active_record2/slugged.rb +30 -0
- data/test/active_record2/slugged_status_test.rb +61 -0
- data/test/active_record2/sti_test.rb +22 -0
- data/test/active_record2/support/database.mysql.yml +4 -0
- data/test/{support/database.yml.postgres → active_record2/support/database.postgres.yml} +0 -0
- data/test/{support/database.yml.sqlite3 → active_record2/support/database.sqlite3.yml} +0 -0
- data/test/{support → active_record2/support}/models.rb +28 -0
- data/test/active_record2/tasks_test.rb +82 -0
- data/test/active_record2/test_helper.rb +107 -0
- data/test/friendly_id_test.rb +23 -0
- data/test/slug_string_test.rb +74 -0
- data/test/test_helper.rb +7 -102
- metadata +64 -56
- data/History.txt +0 -194
- data/README.rdoc +0 -385
- data/generators/friendly_id_20_upgrade/friendly_id_20_upgrade_generator.rb +0 -12
- data/generators/friendly_id_20_upgrade/templates/upgrade_friendly_id_to_20.rb +0 -19
- data/init.rb +0 -1
- data/lib/friendly_id/helpers.rb +0 -12
- data/lib/friendly_id/non_sluggable_class_methods.rb +0 -34
- data/lib/friendly_id/non_sluggable_instance_methods.rb +0 -45
- data/lib/friendly_id/slug.rb +0 -98
- data/lib/friendly_id/sluggable_class_methods.rb +0 -110
- data/lib/friendly_id/sluggable_instance_methods.rb +0 -161
- data/lib/friendly_id/tasks.rb +0 -56
- data/lib/tasks/friendly_id.rake +0 -25
- data/lib/tasks/friendly_id.rb +0 -1
- data/test/cached_slug_test.rb +0 -109
- data/test/custom_slug_normalizer_test.rb +0 -36
- data/test/non_slugged_test.rb +0 -99
- data/test/scoped_model_test.rb +0 -64
- data/test/slug_test.rb +0 -105
- data/test/slugged_model_test.rb +0 -348
- data/test/sti_test.rb +0 -49
- data/test/tasks_test.rb +0 -105
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "active_record2", "configuration")
|
2
|
+
require File.join(File.dirname(__FILE__), "active_record2", "finders")
|
3
|
+
require File.join(File.dirname(__FILE__), "active_record2", "simple_model")
|
4
|
+
require File.join(File.dirname(__FILE__), "active_record2", "slugged_model")
|
5
|
+
require File.join(File.dirname(__FILE__), "active_record2", "slug")
|
6
|
+
require File.join(File.dirname(__FILE__), "active_record2", "tasks")
|
7
|
+
|
8
|
+
module FriendlyId
|
9
|
+
|
10
|
+
module ActiveRecord2
|
11
|
+
|
12
|
+
include FriendlyId::Base
|
13
|
+
|
14
|
+
def has_friendly_id(method, options = {}, &block)
|
15
|
+
class_inheritable_accessor :friendly_id_config
|
16
|
+
write_inheritable_attribute :friendly_id_config, Configuration.new(self,
|
17
|
+
method, options.merge(:normalizer => block))
|
18
|
+
if friendly_id_config.use_slug?
|
19
|
+
include SluggedModel
|
20
|
+
else
|
21
|
+
include SimpleModel
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Prevent the cached_slug column from being accidentally or maliciously
|
28
|
+
# overwritten. Note that +attr_protected+ is used to protect the cached_slug
|
29
|
+
# column, unless you have already invoked +attr_accessible+. So if you
|
30
|
+
# wish to use +attr_accessible+, you must invoke it BEFORE you invoke
|
31
|
+
# {#has_friendly_id} in your class.
|
32
|
+
def protect_friendly_id_attributes
|
33
|
+
# only protect the column if the class is not already using attributes_accessible
|
34
|
+
if !accessible_attributes
|
35
|
+
if friendly_id_config.custom_cache_column?
|
36
|
+
attr_protected friendly_id_config.cache_column
|
37
|
+
end
|
38
|
+
attr_protected :cached_slug
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class ActiveRecord::Base
|
46
|
+
extend FriendlyId::ActiveRecord2
|
47
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
module ActiveRecord2
|
3
|
+
|
4
|
+
class Configuration < FriendlyId::Configuration
|
5
|
+
|
6
|
+
# The column used to cache the friendly_id string. If no column is specified,
|
7
|
+
# FriendlyId will look for a column named +cached_slug+ and use it automatically
|
8
|
+
# if it exists. If for some reason you have a column named +cached_slug+
|
9
|
+
# but don't want FriendlyId to modify it, pass the option
|
10
|
+
# +:cache_column => false+ to {FriendlyId::ActiveRecord2#has_friendly_id has_friendly_id}.
|
11
|
+
attr_accessor :cache_column
|
12
|
+
|
13
|
+
# An array of classes for which the configured class serves as a
|
14
|
+
# FriendlyId scope.
|
15
|
+
attr_reader :child_scopes
|
16
|
+
|
17
|
+
attr_reader :custom_cache_column
|
18
|
+
|
19
|
+
def cache_column
|
20
|
+
return @cache_column if defined?(@cache_column)
|
21
|
+
@cache_column = autodiscover_cache_column
|
22
|
+
end
|
23
|
+
|
24
|
+
def cache_column?
|
25
|
+
!! cache_column
|
26
|
+
end
|
27
|
+
|
28
|
+
def cache_column=(cache_column)
|
29
|
+
@cache_column = cache_column
|
30
|
+
@custom_cache_column = cache_column
|
31
|
+
end
|
32
|
+
|
33
|
+
def cache_finders?
|
34
|
+
!! cache_column
|
35
|
+
end
|
36
|
+
|
37
|
+
def child_scopes
|
38
|
+
@child_scopes ||= associated_friendly_classes.select { |klass| klass.friendly_id_config.scopes_over?(configured_class) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def custom_cache_column?
|
42
|
+
!! custom_cache_column
|
43
|
+
end
|
44
|
+
|
45
|
+
def scope_for(record)
|
46
|
+
scope? ? record.send(scope).to_param : nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def scopes_over?(klass)
|
50
|
+
scope? && scope == klass.to_s.underscore.to_sym
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def autodiscover_cache_column
|
56
|
+
:cached_slug if configured_class.columns.any? { |column| column.name == 'cached_slug' }
|
57
|
+
end
|
58
|
+
|
59
|
+
def associated_friendly_classes
|
60
|
+
configured_class.reflect_on_all_associations.select { |assoc|
|
61
|
+
assoc.klass.uses_friendly_id? }.map(&:klass)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
|
3
|
+
# The adapter for Ruby on Rails's ActiveRecord. Compatible with AR 2.2.x -
|
4
|
+
# 2.3.x.
|
5
|
+
module ActiveRecord2
|
6
|
+
|
7
|
+
# The classes in this module are used internally by FriendlyId, and exist
|
8
|
+
# largely to avoid polluting the ActiveRecord models with too many
|
9
|
+
# FriendlyId-specific methods.
|
10
|
+
module Finders
|
11
|
+
|
12
|
+
# FinderProxy is used to choose which finder class to instantiate;
|
13
|
+
# depending on the model_class's +friendly_id_config+ and the options
|
14
|
+
# passed into the constructor, it will decide whether to use simple or
|
15
|
+
# slugged finder, a single or multiple finder, and in the case of slugs,
|
16
|
+
# a cached or uncached finder.
|
17
|
+
class FinderProxy
|
18
|
+
|
19
|
+
attr_reader :finder
|
20
|
+
attr :finder_class
|
21
|
+
attr :ids
|
22
|
+
attr :model_class
|
23
|
+
attr :options
|
24
|
+
|
25
|
+
def initialize(ids, model_class, options={})
|
26
|
+
@ids = ids
|
27
|
+
@model_class = model_class
|
28
|
+
@options = options
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing(symbol, *args)
|
32
|
+
finder.send(symbol, *args)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Perform the find query.
|
36
|
+
def finder
|
37
|
+
@finder ||= finder_class.new(ids, model_class, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def finder_class
|
43
|
+
@finder_class ||= slugged? ? slugged_finder_class : simple_finder_class
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def cache_available?
|
49
|
+
!! model_class.friendly_id_config.cache_column
|
50
|
+
end
|
51
|
+
|
52
|
+
def multiple?
|
53
|
+
ids.kind_of? Array
|
54
|
+
end
|
55
|
+
|
56
|
+
def multiple_slugged_finder_class
|
57
|
+
use_cache? ? SluggedModel::CachedMultipleFinder : SluggedModel::MultipleFinder
|
58
|
+
end
|
59
|
+
|
60
|
+
def simple_finder_class
|
61
|
+
multiple? ? SimpleModel::MultipleFinder : SimpleModel::SingleFinder
|
62
|
+
end
|
63
|
+
|
64
|
+
def slugged?
|
65
|
+
!! model_class.friendly_id_config.use_slug?
|
66
|
+
end
|
67
|
+
|
68
|
+
def slugged_finder_class
|
69
|
+
multiple? ? multiple_slugged_finder_class : single_slugged_finder_class
|
70
|
+
end
|
71
|
+
|
72
|
+
def scoped?
|
73
|
+
!! options[:scope]
|
74
|
+
end
|
75
|
+
|
76
|
+
def single_slugged_finder_class
|
77
|
+
use_cache? ? SluggedModel::CachedSingleFinder : SluggedModel::SingleFinder
|
78
|
+
end
|
79
|
+
|
80
|
+
def use_cache?
|
81
|
+
cache_available? and !scoped?
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
# Wraps finds for multiple records using an array of friendly_ids.
|
87
|
+
# @abstract
|
88
|
+
module Multiple
|
89
|
+
|
90
|
+
attr_reader :friendly_ids, :results, :unfriendly_ids
|
91
|
+
|
92
|
+
def initialize(ids, model_class, options={})
|
93
|
+
@friendly_ids, @unfriendly_ids = ids.partition {|id| FriendlyId::Finders::Base.friendly?(id) }
|
94
|
+
@unfriendly_ids = @unfriendly_ids.map {|id| id.class.respond_to?(:friendly_id_config) ? id.id : id}
|
95
|
+
super
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# An error message to use when the wrong number of results was returned.
|
101
|
+
def error_message
|
102
|
+
"Couldn't find all %s with IDs (%s) AND %s (found %d results, but was looking for %d)" % [
|
103
|
+
model_class.name.pluralize,
|
104
|
+
ids.join(', '),
|
105
|
+
sanitize_sql(options[:conditions]),
|
106
|
+
results.size,
|
107
|
+
expected_size
|
108
|
+
]
|
109
|
+
end
|
110
|
+
|
111
|
+
# How many results do we expect?
|
112
|
+
def expected_size
|
113
|
+
limited? ? limit : offset_size
|
114
|
+
end
|
115
|
+
|
116
|
+
# The limit option passed to the find.
|
117
|
+
def limit
|
118
|
+
options[:limit]
|
119
|
+
end
|
120
|
+
|
121
|
+
# Is the find limited?
|
122
|
+
def limited?
|
123
|
+
offset_size > limit if limit
|
124
|
+
end
|
125
|
+
|
126
|
+
# The offset used for the find. If no offset was passed, 0 is returned.
|
127
|
+
def offset
|
128
|
+
options[:offset].to_i
|
129
|
+
end
|
130
|
+
|
131
|
+
# The number of ids, minus the offset.
|
132
|
+
def offset_size
|
133
|
+
ids.size - offset
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
module ActiveRecord2
|
3
|
+
|
4
|
+
module SimpleModel
|
5
|
+
|
6
|
+
# Some basic methods common to {MultipleFinder} and {SingleFinder}.
|
7
|
+
module SimpleFinder
|
8
|
+
|
9
|
+
# The column used to store the friendly_id.
|
10
|
+
def column
|
11
|
+
"#{table_name}.#{friendly_id_config.column}"
|
12
|
+
end
|
13
|
+
|
14
|
+
# The model's fully-qualified and quoted primary key.
|
15
|
+
def primary_key
|
16
|
+
"#{quoted_table_name}.#{model_class.send :primary_key}"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class MultipleFinder
|
22
|
+
|
23
|
+
include FriendlyId::Finders::Base
|
24
|
+
include FriendlyId::ActiveRecord2::Finders::Multiple
|
25
|
+
include SimpleFinder
|
26
|
+
|
27
|
+
def find
|
28
|
+
@results = with_scope(:find => options) { find_every :conditions => conditions }
|
29
|
+
raise(::ActiveRecord::RecordNotFound, error_message) if @results.size != expected_size
|
30
|
+
friendly_results.each { |result| result.friendly_id_status.name = result.to_param }
|
31
|
+
@results
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def conditions
|
37
|
+
["#{primary_key} IN (?) OR #{column} IN (?)", unfriendly_ids, friendly_ids]
|
38
|
+
end
|
39
|
+
|
40
|
+
def friendly_results
|
41
|
+
results.select { |result| friendly_ids.include? result.to_param }
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class SingleFinder
|
47
|
+
|
48
|
+
include FriendlyId::Finders::Base
|
49
|
+
include FriendlyId::Finders::Single
|
50
|
+
include SimpleFinder
|
51
|
+
|
52
|
+
def find
|
53
|
+
result = with_scope(:find => find_options) { find_initial options }
|
54
|
+
raise ::ActiveRecord::RecordNotFound.new if friendly? && !result
|
55
|
+
result.friendly_id_status.name = id if result
|
56
|
+
result
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def find_options
|
62
|
+
@find_options ||= {:conditions => {column => id}}
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# The methods in this module override ActiveRecord's +find_one+ and
|
68
|
+
# +find_some+ to add FriendlyId's features.
|
69
|
+
module FinderMethods
|
70
|
+
protected
|
71
|
+
|
72
|
+
def find_one(id, options)
|
73
|
+
finder = Finders::FinderProxy.new(id, self, options)
|
74
|
+
!finder.friendly? ? super : finder.find
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_some(ids_and_names, options)
|
78
|
+
Finders::FinderProxy.new(ids_and_names, self, options).find
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# These methods will be removed in FriendlyId 3.0.
|
83
|
+
module DeprecatedMethods
|
84
|
+
|
85
|
+
# Was the record found using one of its friendly ids?
|
86
|
+
# @deprecated Please use #friendly_id_status.friendly?
|
87
|
+
def found_using_friendly_id?
|
88
|
+
warn("found_using_friendly_id? is deprecated and will be removed in 3.0. Please use #friendly_id_status.friendly?")
|
89
|
+
friendly_id_status.friendly?
|
90
|
+
end
|
91
|
+
|
92
|
+
# Was the record found using its numeric id?
|
93
|
+
# @deprecated Please use #friendly_id_status.numeric?
|
94
|
+
def found_using_numeric_id?
|
95
|
+
warn("found_using_numeric_id is deprecated and will be removed in 3.0. Please use #friendly_id_status.numeric?")
|
96
|
+
friendly_id_status.numeric?
|
97
|
+
end
|
98
|
+
|
99
|
+
# Was the record found using an old friendly id, or its numeric id?
|
100
|
+
# @deprecated Please use !#friendly_id_status.best?
|
101
|
+
def has_better_id?
|
102
|
+
warn("has_better_id? is deprecated and will be removed in 3.0. Please use !#friendly_id_status.best?")
|
103
|
+
! friendly_id_status.best?
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.included(base)
|
109
|
+
base.class_eval do
|
110
|
+
column = friendly_id_config.column
|
111
|
+
validate :validate_friendly_id
|
112
|
+
validates_presence_of column
|
113
|
+
validates_length_of column, :maximum => friendly_id_config.max_length
|
114
|
+
after_update :update_scopes
|
115
|
+
extend FinderMethods
|
116
|
+
include DeprecatedMethods
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Get the {FriendlyId::Status} after the find has been performed.
|
121
|
+
def friendly_id_status
|
122
|
+
@friendly_id_status ||= Status.new :record => self
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns the friendly_id.
|
126
|
+
def friendly_id
|
127
|
+
send friendly_id_config.column
|
128
|
+
end
|
129
|
+
alias best_id friendly_id
|
130
|
+
|
131
|
+
# Returns the friendly id, or if none is available, the numeric id.
|
132
|
+
def to_param
|
133
|
+
(friendly_id || id).to_s
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
# The old and new values for the friendly_id column.
|
139
|
+
def friendly_id_changes
|
140
|
+
changes[friendly_id_config.column.to_s]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Update the slugs for any model that is using this model as its
|
144
|
+
# FriendlyId scope.
|
145
|
+
def update_scopes
|
146
|
+
if changes = friendly_id_changes
|
147
|
+
friendly_id_config.child_scopes.each do |klass|
|
148
|
+
Slug.update_all "scope = '#{changes[1]}'", ["sluggable_type = ? AND scope = ?", klass.to_s, changes[0]]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def validate_friendly_id
|
154
|
+
if result = friendly_id_config.reserved_error_message(friendly_id)
|
155
|
+
self.errors.add(*result)
|
156
|
+
return false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
module ActiveRecord2
|
3
|
+
|
4
|
+
module DeprecatedSlugMethods
|
5
|
+
# @deprecated Please use String#parse_friendly_id
|
6
|
+
def parse(string)
|
7
|
+
warn("Slug#parse is deprecated and will be removed in FriendlyId 3.0. Please use String#parse_friendly_id.")
|
8
|
+
string.to_s.parse_friendly_id
|
9
|
+
end
|
10
|
+
|
11
|
+
# @deprecated Please use SlugString#normalize.
|
12
|
+
def normalize(slug_text)
|
13
|
+
warn("Slug#normalize is deprecated and will be removed in FriendlyId 3.0. Please use SlugString#normalize.")
|
14
|
+
raise BlankError if slug_text.blank?
|
15
|
+
SlugString.new(slug_text.to_s).normalize.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
# @deprecated Please use SlugString#approximate_ascii."
|
19
|
+
def strip_diacritics(string)
|
20
|
+
warn("Slug#strip_diacritics is deprecated and will be removed in FriendlyId 3.0. Please use SlugString#approximate_ascii.")
|
21
|
+
raise BlankError if string.blank?
|
22
|
+
SlugString.new(string).approximate_ascii
|
23
|
+
end
|
24
|
+
|
25
|
+
# @deprecated Please use SlugString#to_ascii.
|
26
|
+
def strip_non_ascii(string)
|
27
|
+
warn("Slug#strip_non_ascii is deprecated and will be removed in FriendlyId 3.0. Please use SlugString#to_ascii.")
|
28
|
+
raise BlankError if string.blank?
|
29
|
+
SlugString.new(string).to_ascii
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
# A Slug is a unique, human-friendly identifier for an ActiveRecord.
|
39
|
+
class Slug < ::ActiveRecord::Base
|
40
|
+
|
41
|
+
extend FriendlyId::ActiveRecord2::DeprecatedSlugMethods
|
42
|
+
|
43
|
+
table_name = "slugs"
|
44
|
+
belongs_to :sluggable, :polymorphic => true
|
45
|
+
before_save :enable_name_reversion, :set_sequence
|
46
|
+
validate :validate_name
|
47
|
+
named_scope :similar_to, lambda {|slug| {:conditions => {
|
48
|
+
:name => slug.name,
|
49
|
+
:scope => slug.scope,
|
50
|
+
:sluggable_type => slug.sluggable_type
|
51
|
+
},
|
52
|
+
:order => "sequence ASC"
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
# Whether this slug is the most recent of its owner's slugs.
|
57
|
+
def current?
|
58
|
+
sluggable.slug == self
|
59
|
+
end
|
60
|
+
|
61
|
+
def outdated?
|
62
|
+
!current?
|
63
|
+
end
|
64
|
+
|
65
|
+
# @deprecated Please used Slug#current?
|
66
|
+
def is_most_recent?
|
67
|
+
warn("Slug#is_most_recent? is deprecated and will be removed in FriendlyId 3.0. Please use Slug#current?")
|
68
|
+
current?
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_friendly_id
|
72
|
+
sequence > 1 ? friendly_id_with_sequence : name
|
73
|
+
end
|
74
|
+
|
75
|
+
# Raise a FriendlyId::SlugGenerationError if the slug name is blank.
|
76
|
+
def validate_name
|
77
|
+
if name.blank?
|
78
|
+
raise FriendlyId::BlankError.new("slug.name can not be blank.")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# If we're renaming back to a previously used friendly_id, delete the
|
85
|
+
# slug so that we can recycle the name without having to use a sequence.
|
86
|
+
def enable_name_reversion
|
87
|
+
sluggable.slugs.find_all_by_name_and_scope(name, scope).each { |slug| slug.destroy }
|
88
|
+
end
|
89
|
+
|
90
|
+
def friendly_id_with_sequence
|
91
|
+
"#{name}#{separator}#{sequence}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def similar_to_other_slugs?
|
95
|
+
!similar_slugs.empty?
|
96
|
+
end
|
97
|
+
|
98
|
+
def similar_slugs
|
99
|
+
self.class.similar_to(self)
|
100
|
+
end
|
101
|
+
|
102
|
+
def separator
|
103
|
+
sluggable.friendly_id_config.sequence_separator
|
104
|
+
end
|
105
|
+
|
106
|
+
def set_sequence
|
107
|
+
return unless new_record?
|
108
|
+
self.sequence = similar_slugs.last.sequence.succ if similar_to_other_slugs?
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|