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,317 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
module ActiveRecord2
|
3
|
+
module SluggedModel
|
4
|
+
|
5
|
+
module SluggedFinder
|
6
|
+
# Whether :include => :slugs has been passed as an option.
|
7
|
+
def slugs_included?
|
8
|
+
[*(options[:include] or [])].flatten.include?(:slugs)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class MultipleFinder
|
13
|
+
|
14
|
+
include FriendlyId::Finders::Base
|
15
|
+
include FriendlyId::ActiveRecord2::Finders::Multiple
|
16
|
+
include SluggedFinder
|
17
|
+
|
18
|
+
attr_reader :slugs
|
19
|
+
|
20
|
+
def find
|
21
|
+
@results = with_scope(:find => find_options) { all options }.uniq
|
22
|
+
raise ::ActiveRecord::RecordNotFound, error_message if @results.size != expected_size
|
23
|
+
@results.each {|result| result.friendly_id_status.name = slug_for(result)}
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def find_conditions
|
29
|
+
slugs
|
30
|
+
# [unfriendly_find_conditions, friendly_find_conditions].compact.join(" OR ")
|
31
|
+
ids = (unfriendly_ids + sluggable_ids).join(",")
|
32
|
+
"%s IN (%s)" % ["#{quoted_table_name}.#{primary_key}", ids]
|
33
|
+
end
|
34
|
+
|
35
|
+
def friendly_find_conditions
|
36
|
+
"slugs.id IN (%s)" % slugs.compact.to_s(:db) if slugs?
|
37
|
+
end
|
38
|
+
|
39
|
+
def find_options
|
40
|
+
{:select => "#{table_name}.*", :conditions => find_conditions,
|
41
|
+
:joins => slugs_included? ? options[:joins] : :slugs}
|
42
|
+
end
|
43
|
+
|
44
|
+
def sluggable_ids
|
45
|
+
if !@sluggable_ids
|
46
|
+
@sluggable_ids ||= []
|
47
|
+
slugs
|
48
|
+
end
|
49
|
+
@sluggable_ids
|
50
|
+
end
|
51
|
+
|
52
|
+
def slugs
|
53
|
+
@sluggable_ids ||= []
|
54
|
+
@slugs ||= friendly_ids.map do |friendly_id|
|
55
|
+
name, sequence = friendly_id.parse_friendly_id(friendly_id_config.sequence_separator)
|
56
|
+
slug = Slug.first :conditions => {
|
57
|
+
:name => name,
|
58
|
+
:scope => scope,
|
59
|
+
:sequence => sequence,
|
60
|
+
:sluggable_type => base_class.name
|
61
|
+
}
|
62
|
+
sluggable_ids << slug.sluggable_id if slug
|
63
|
+
slug
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def slugs?
|
68
|
+
!slugs.empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
def slug_for(result)
|
72
|
+
slugs.select {|slug| result.id == slug.sluggable_id}.first
|
73
|
+
end
|
74
|
+
|
75
|
+
def unfriendly_find_conditions
|
76
|
+
"%s IN (%s)" % ["#{quoted_table_name}.#{primary_key}", unfriendly_ids.join(",")] if unfriendly_ids?
|
77
|
+
end
|
78
|
+
|
79
|
+
def unfriendly_ids?
|
80
|
+
! unfriendly_ids.empty?
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
# Performs a find a single friendly_id using the cached_slug column,
|
86
|
+
# if available. This is significantly faster, and can be used in all
|
87
|
+
# circumstances unless the +:scope+ argument is present.
|
88
|
+
class CachedMultipleFinder < SimpleModel::MultipleFinder
|
89
|
+
# The column used to store the cached slug.
|
90
|
+
def column
|
91
|
+
"#{table_name}.#{friendly_id_config.cache_column}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class SingleFinder
|
96
|
+
|
97
|
+
include FriendlyId::Finders::Base
|
98
|
+
include FriendlyId::Finders::Single
|
99
|
+
include SluggedFinder
|
100
|
+
|
101
|
+
def find
|
102
|
+
result = with_scope({:find => find_options}) { find_initial options }
|
103
|
+
raise ::ActiveRecord::RecordNotFound.new if friendly? and !result
|
104
|
+
result.friendly_id_status.name = name if result
|
105
|
+
result
|
106
|
+
rescue ::ActiveRecord::RecordNotFound => @error
|
107
|
+
friendly_id_config.scope? ? raise_scoped_error : (raise @error)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def find_options
|
113
|
+
slug_table = Slug.table_name
|
114
|
+
{
|
115
|
+
:select => "#{model_class.table_name}.*",
|
116
|
+
:joins => slugs_included? ? options[:joins] : :slugs,
|
117
|
+
:conditions => {
|
118
|
+
"#{slug_table}.name" => name,
|
119
|
+
"#{slug_table}.scope" => scope,
|
120
|
+
"#{slug_table}.sequence" => sequence
|
121
|
+
}
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def raise_scoped_error
|
126
|
+
scope_message = options[:scope] || "expected, but none given"
|
127
|
+
message = "%s, scope: %s" % [@error.message, scope_message]
|
128
|
+
raise ::ActiveRecord::RecordNotFound, message
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
# Performs a find for multiple friendly_ids using the cached_slug column,
|
134
|
+
# if available. This is significantly faster, and can be used in all
|
135
|
+
# circumstances unless the +:scope+ argument is present.
|
136
|
+
class CachedSingleFinder < SimpleModel::SingleFinder
|
137
|
+
|
138
|
+
# The column used to store the cached slug.
|
139
|
+
def column
|
140
|
+
"#{table_name}.#{friendly_id_config.cache_column}"
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
# The methods in this module override ActiveRecord's +find_one+ and
|
146
|
+
# +find_some+ to add FriendlyId's features.
|
147
|
+
module FinderMethods
|
148
|
+
|
149
|
+
protected
|
150
|
+
|
151
|
+
def find_one(id_or_name, options)
|
152
|
+
finder = Finders::FinderProxy.new(id_or_name, self, options)
|
153
|
+
finder.unfriendly? ? super : finder.find or super
|
154
|
+
end
|
155
|
+
|
156
|
+
def find_some(ids_and_names, options)
|
157
|
+
Finders::FinderProxy.new(ids_and_names, self, options).find
|
158
|
+
end
|
159
|
+
|
160
|
+
# Since Rails goes out of its way to make these options completely
|
161
|
+
# inaccessible, we have to copy them here.
|
162
|
+
def validate_find_options(options)
|
163
|
+
options.assert_valid_keys([:conditions, :include, :joins, :limit, :offset,
|
164
|
+
:order, :select, :readonly, :group, :from, :lock, :having, :scope])
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
# These methods will be removed in FriendlyId 3.0.
|
170
|
+
module DeprecatedMethods
|
171
|
+
|
172
|
+
# @deprecated Please use #to_param
|
173
|
+
def best_id
|
174
|
+
warn("best_id is deprecated and will be removed in 3.0. Please use #to_param.")
|
175
|
+
to_param
|
176
|
+
end
|
177
|
+
|
178
|
+
# @deprecated Please use #friendly_id_status.slug.
|
179
|
+
def finder_slug
|
180
|
+
warn("finder_slug is deprecated and will be removed in 3.0. Please use #friendly_id_status.slug.")
|
181
|
+
friendly_id_status.slug
|
182
|
+
end
|
183
|
+
|
184
|
+
# Was the record found using one of its friendly ids?
|
185
|
+
# @deprecated Please use #friendly_id_status.friendly?
|
186
|
+
def found_using_friendly_id?
|
187
|
+
warn("found_using_friendly_id? is deprecated and will be removed in 3.0. Please use #friendly_id_status.friendly?")
|
188
|
+
friendly_id_status.friendly?
|
189
|
+
end
|
190
|
+
|
191
|
+
# Was the record found using its numeric id?
|
192
|
+
# @deprecated Please use #friendly_id_status.numeric?
|
193
|
+
def found_using_numeric_id?
|
194
|
+
warn("found_using_numeric_id is deprecated and will be removed in 3.0. Please use #friendly_id_status.numeric?")
|
195
|
+
friendly_id_status.numeric?
|
196
|
+
end
|
197
|
+
|
198
|
+
# Was the record found using an old friendly id?
|
199
|
+
# @deprecated Please use #friendly_id_status.outdated?
|
200
|
+
def found_using_outdated_friendly_id?
|
201
|
+
warn("found_using_outdated_friendly_id is deprecated and will be removed in 3.0. Please use #friendly_id_status.outdated?")
|
202
|
+
friendly_id_status.outdated?
|
203
|
+
end
|
204
|
+
|
205
|
+
# Was the record found using an old friendly id, or its numeric id?
|
206
|
+
# @deprecated Please use !#friendly_id_status.best?
|
207
|
+
def has_better_id?
|
208
|
+
warn("has_better_id? is deprecated and will be removed in 3.0. Please use !#friendly_id_status.best?")
|
209
|
+
! friendly_id_status.best?
|
210
|
+
end
|
211
|
+
|
212
|
+
# @deprecated Please use #slug?
|
213
|
+
def has_a_slug?
|
214
|
+
warn("has_a_slug? is deprecated and will be removed in 3.0. Please use #slug?")
|
215
|
+
slug?
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.included(base)
|
221
|
+
base.class_eval do
|
222
|
+
has_many :slugs, :order => 'id DESC', :as => :sluggable, :dependent => :destroy
|
223
|
+
before_save :build_slug
|
224
|
+
after_save :set_slug_cache
|
225
|
+
after_update :update_scope
|
226
|
+
after_update :update_dependent_scopes
|
227
|
+
protect_friendly_id_attributes
|
228
|
+
extend FinderMethods
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
include FriendlyId::Slugged::Model
|
233
|
+
include DeprecatedMethods
|
234
|
+
|
235
|
+
def find_slug(name)
|
236
|
+
separator = friendly_id_config.sequence_separator
|
237
|
+
slugs.find_by_name_and_sequence(*name.to_s.parse_friendly_id(separator))
|
238
|
+
end
|
239
|
+
|
240
|
+
# The model instance's current {FriendlyId::ActiveRecord2::Slug slug}.
|
241
|
+
def slug
|
242
|
+
return @slug if new_record?
|
243
|
+
@slug ||= slugs.first(:order => "id DESC")
|
244
|
+
end
|
245
|
+
|
246
|
+
# Set the slug.
|
247
|
+
def slug=(slug)
|
248
|
+
@new_friendly_id = slug.to_friendly_id unless slug.nil?
|
249
|
+
super
|
250
|
+
end
|
251
|
+
|
252
|
+
# Returns the friendly id, or if none is available, the numeric id.
|
253
|
+
def to_param
|
254
|
+
friendly_id_config.cache_column ? to_param_from_cache : to_param_from_slug
|
255
|
+
end
|
256
|
+
|
257
|
+
private
|
258
|
+
|
259
|
+
def scope_changed?
|
260
|
+
friendly_id_config.scope? && send(friendly_id_config.scope).to_param != slug.scope
|
261
|
+
end
|
262
|
+
|
263
|
+
# Respond with the cached value if available.
|
264
|
+
def to_param_from_cache
|
265
|
+
read_attribute(friendly_id_config.cache_column) || id.to_s
|
266
|
+
end
|
267
|
+
|
268
|
+
# Respond with the slugged value if available.
|
269
|
+
def to_param_from_slug
|
270
|
+
slug? ? slug.to_friendly_id : id.to_s
|
271
|
+
end
|
272
|
+
|
273
|
+
# Build the new slug using the generated friendly id.
|
274
|
+
def build_slug
|
275
|
+
return unless new_slug_needed?
|
276
|
+
self.slug = slugs.build :name => slug_text.to_s, :scope => friendly_id_config.scope_for(self)
|
277
|
+
end
|
278
|
+
|
279
|
+
# Reset the cached friendly_id?
|
280
|
+
def new_cache_needed?
|
281
|
+
uses_slug_cache? && send(friendly_id_config.cache_column) != slug.to_friendly_id
|
282
|
+
end
|
283
|
+
|
284
|
+
# Reset the cached friendly_id.
|
285
|
+
def set_slug_cache
|
286
|
+
if new_cache_needed?
|
287
|
+
send "#{friendly_id_config.cache_column}=", slug.to_friendly_id
|
288
|
+
send :update_without_callbacks
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def update_scope
|
293
|
+
return unless scope_changed?
|
294
|
+
slug.update_attributes :scope => send(friendly_id_config.scope).to_param
|
295
|
+
rescue ActiveRecord::StatementInvalid
|
296
|
+
slug.update_attributes :sequence => Slug.similar_to(slug).first.sequence.succ
|
297
|
+
end
|
298
|
+
|
299
|
+
# Update the slugs for any model that is using this model as its
|
300
|
+
# FriendlyId scope.
|
301
|
+
def update_dependent_scopes
|
302
|
+
if slugs(true).size > 1 && @new_friendly_id
|
303
|
+
friendly_id_config.child_scopes.each do |klass|
|
304
|
+
Slug.update_all "scope = '#{@new_friendly_id}'", ["sluggable_type = ? AND scope = ?",
|
305
|
+
klass.to_s, slugs.second.to_friendly_id]
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
# Does the model use slug caching?
|
311
|
+
def uses_slug_cache?
|
312
|
+
friendly_id_config.cache_column?
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
class TaskRunner
|
3
|
+
|
4
|
+
attr_accessor :days
|
5
|
+
attr_accessor :klass
|
6
|
+
attr_accessor :task_options
|
7
|
+
|
8
|
+
OLD_SLUG_DAYS = 45
|
9
|
+
|
10
|
+
def initialize(&block)
|
11
|
+
self.klass = ENV["MODEL"]
|
12
|
+
self.days = ENV["DAYS"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(*args)
|
16
|
+
klass.send(*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def days=(days)
|
20
|
+
@days = days.blank? ? OLD_SLUG_DAYS : days.to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def klass=(klass)
|
24
|
+
@klass = klass.to_s.classify.constantize unless klass.blank?
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_slugs
|
28
|
+
validate_uses_slugs
|
29
|
+
options = {:limit => 100, :include => :slugs, :conditions => "slugs.id IS NULL"}.merge(task_options || {})
|
30
|
+
while records = find(:all, options) do
|
31
|
+
break if records.size == 0
|
32
|
+
records.each do |record|
|
33
|
+
record.save!
|
34
|
+
yield(record) if block_given?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete_slugs
|
40
|
+
validate_uses_slugs
|
41
|
+
Slug.destroy_all(["sluggable_type = ?", klass.to_s])
|
42
|
+
if column = friendly_id_config.cache_column
|
43
|
+
update_all("#{column} = NULL")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete_old_slugs
|
48
|
+
conditions = ["created_at < ?", DateTime.now - days.days]
|
49
|
+
if klass
|
50
|
+
conditions[0] << " AND sluggable_type = ?"
|
51
|
+
conditions << klass.to_s
|
52
|
+
end
|
53
|
+
Slug.all(:conditions => conditions).select(&:outdated?).map(&:destroy)
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_uses_slugs
|
57
|
+
unless friendly_id_config.use_slug?
|
58
|
+
raise "Class '%s' doesn't use slugs" % klass.to_s
|
59
|
+
end
|
60
|
+
rescue NoMethodError
|
61
|
+
raise "Class '%s' doesn't use FriendlyId" % klass.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
namespace :friendly_id do
|
2
|
+
desc "Make slugs for a model."
|
3
|
+
task :make_slugs => :environment do
|
4
|
+
FriendlyId::TaskRunner.new.make_slugs do |record|
|
5
|
+
puts "%s(%d): friendly_id set to '%s'" % [record.class.to_s, record.id, record.slug.name]
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Regenereate slugs for a model."
|
10
|
+
task :redo_slugs => :environment do
|
11
|
+
FriendlyId::TaskRunner.new.delete_slugs
|
12
|
+
Rake::Task["friendly_id:make_slugs"].invoke
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Kill obsolete slugs older than DAYS=45 days."
|
16
|
+
task :remove_old_slugs => :environment do
|
17
|
+
FriendlyId::TaskRunner.new.delete_old_slugs
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
|
3
|
+
# This class is not intended to be used on its own, it is used internally
|
4
|
+
# by `has_friendly_id` to store a model's configuration and
|
5
|
+
# configuration-related methods.
|
6
|
+
#
|
7
|
+
# The arguments accepted by +has_friendly_id+ correspond to the writeable
|
8
|
+
# instance attributes of this class; please see the description of the
|
9
|
+
# attributes below for information on the possible options.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# has_friendly_id :name,
|
13
|
+
# :use_slug => true,
|
14
|
+
# :max_length => 150,
|
15
|
+
# :approximate_ascii => true,
|
16
|
+
# :ascii_approximation_options => :german,
|
17
|
+
# :sequence_separator => ":",
|
18
|
+
# :reserved_words => ["reserved", "words"],
|
19
|
+
# :scope => :country,
|
20
|
+
# :cache_column => :my_cache_column_name
|
21
|
+
# # etc.
|
22
|
+
class Configuration
|
23
|
+
|
24
|
+
DEFAULTS = {
|
25
|
+
:ascii_approximation_options => [],
|
26
|
+
:max_length => 255,
|
27
|
+
:reserved_words => ["index", "new"],
|
28
|
+
:reserved_message => 'can not be "%s"',
|
29
|
+
:sequence_separator => "--"
|
30
|
+
}
|
31
|
+
|
32
|
+
# Strip diacritics from Western characters.
|
33
|
+
attr_accessor :approximate_ascii
|
34
|
+
|
35
|
+
# Locale-type options for ASCII approximations. These can be any of the
|
36
|
+
# values supported by {SlugString#approximate_ascii!}.
|
37
|
+
attr_accessor :ascii_approximation_options
|
38
|
+
|
39
|
+
# The class that's using the configuration.
|
40
|
+
attr_reader :configured_class
|
41
|
+
|
42
|
+
# The maximum allowed length for a friendly_id string. This is checked *after* a
|
43
|
+
# string is processed by FriendlyId to remove spaces, special characters, etc.
|
44
|
+
attr_accessor :max_length
|
45
|
+
|
46
|
+
# The method or column that will be used as the basis of the friendly_id string.
|
47
|
+
attr_reader :method
|
48
|
+
alias :column :method
|
49
|
+
|
50
|
+
# A block or proc through which to filter the friendly_id text.
|
51
|
+
# This method will be removed from FriendlyId 3.0.
|
52
|
+
# @deprecated Please override the +normalize_friendly_id+
|
53
|
+
# method in your model class rather than passing a block to `has_friendly_id`.
|
54
|
+
attr_accessor :normalizer
|
55
|
+
|
56
|
+
# The message shown when a reserved word is used.
|
57
|
+
# @see #reserved_words
|
58
|
+
attr_accessor :reserved_message
|
59
|
+
|
60
|
+
# Array of words that are reserved and can't be used as friendly_id strings.
|
61
|
+
# If a listed word is used in a sluggable model, it will raise a
|
62
|
+
# FriendlyId::SlugGenerationError. For Rails applications, you are recommended
|
63
|
+
# to include "index" and "new", which used as the defaults unless overridden.
|
64
|
+
attr_accessor :reserved_words
|
65
|
+
|
66
|
+
# The method or relation to use as the friendly_id's scope.
|
67
|
+
attr_accessor :scope
|
68
|
+
|
69
|
+
# The string that separates slug names from slug sequences. Defaults to "--".
|
70
|
+
attr_accessor :sequence_separator
|
71
|
+
|
72
|
+
# Strip non-ASCII characters from the friendly_id string.
|
73
|
+
attr_accessor :strip_non_ascii
|
74
|
+
|
75
|
+
# Use slugs for storing the friendly_id string.
|
76
|
+
attr_accessor :use_slug
|
77
|
+
alias :use_slugs= :use_slug
|
78
|
+
|
79
|
+
def initialize(configured_class, method, options = nil, &block)
|
80
|
+
@configured_class = configured_class
|
81
|
+
@method = method.to_sym
|
82
|
+
DEFAULTS.merge(options || {}).each do |key, value|
|
83
|
+
self.send "#{key}=".to_sym, value
|
84
|
+
end
|
85
|
+
yield self if block_given?
|
86
|
+
end
|
87
|
+
|
88
|
+
def normalizer=(arg)
|
89
|
+
return if arg.nil?
|
90
|
+
raise("passing a block to has_friendly_id is deprecated and will be removed from 3.0. Please override #friendly_id_normalizer.")
|
91
|
+
@normalizer = arg
|
92
|
+
end
|
93
|
+
|
94
|
+
def reserved_words=(*words)
|
95
|
+
@reserved_words = words.flatten.uniq
|
96
|
+
end
|
97
|
+
|
98
|
+
def reserved?(word)
|
99
|
+
reserved_words.include? word.to_s
|
100
|
+
end
|
101
|
+
|
102
|
+
def reserved_error_message(word)
|
103
|
+
[method, reserved_message % word] if reserved? word
|
104
|
+
end
|
105
|
+
|
106
|
+
# This method will be removed from FriendlyId 3.0.
|
107
|
+
# @deprecated Please use {#reserved_words reserved_words}.
|
108
|
+
def reserved=(*args)
|
109
|
+
warn('The "reserved" option is deprecated and will be removed from FriendlyId 3.0. Please use "reserved_words".')
|
110
|
+
self.reserved_words = *args
|
111
|
+
end
|
112
|
+
|
113
|
+
# This method will be removed from FriendlyId 3.0.
|
114
|
+
# @deprecated Please use {#approximate_ascii approximate_ascii}.
|
115
|
+
def strip_diacritics=(*args)
|
116
|
+
warn('strip_diacritics is deprecated and will be removed from 3.0. Please use #approximate_ascii')
|
117
|
+
self.strip_diacritics = *args
|
118
|
+
end
|
119
|
+
|
120
|
+
%w[approximate_ascii normalizer scope strip_non_ascii use_slug].each do |method|
|
121
|
+
class_eval(<<-EOM)
|
122
|
+
def #{method}?
|
123
|
+
!! #{method}
|
124
|
+
end
|
125
|
+
EOM
|
126
|
+
end
|
127
|
+
|
128
|
+
alias :use_slugs? :use_slug?
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|