friendly_id 2.3.4 → 3.0.0.beta1
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 +10 -0
- data/Contributors.md +1 -0
- data/Guide.md +48 -4
- data/README.md +6 -4
- data/Rakefile +1 -1
- data/extras/extras.rb +1 -1
- data/generators/friendly_id/friendly_id_generator.rb +1 -1
- data/lib/friendly_id.rb +4 -6
- data/lib/friendly_id/{active_record2 → acktive_record}/configuration.rb +2 -2
- data/lib/friendly_id/{active_record2 → acktive_record}/finders.rb +24 -10
- data/lib/friendly_id/{active_record2 → acktive_record}/simple_model.rb +12 -50
- data/lib/friendly_id/acktive_record/slug.rb +66 -0
- data/lib/friendly_id/{active_record2 → acktive_record}/slugged_model.rb +9 -85
- data/lib/friendly_id/{active_record2 → acktive_record}/tasks.rb +5 -2
- data/lib/friendly_id/{active_record2 → acktive_record}/tasks/friendly_id.rake +1 -1
- data/lib/friendly_id/{active_record2.rb → active_record.rb} +18 -13
- data/lib/friendly_id/configuration.rb +11 -26
- data/lib/friendly_id/finders.rb +5 -3
- data/lib/friendly_id/slug_string.rb +11 -10
- data/lib/friendly_id/slugged.rb +11 -4
- data/lib/friendly_id/test.rb +46 -5
- data/lib/friendly_id/version.rb +5 -4
- data/lib/generators/friendly_id_generator.rb +32 -0
- data/rails/init.rb +1 -1
- data/test/{active_record2 → acktive_record}/basic_slugged_model_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/cached_slug_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/core.rb +1 -1
- data/test/{active_record2 → acktive_record}/custom_normalizer_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/custom_table_name_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/scoped_model_test.rb +2 -2
- data/test/{active_record2 → acktive_record}/simple_test.rb +4 -1
- data/test/{active_record2 → acktive_record}/slug_test.rb +0 -0
- data/test/{active_record2 → acktive_record}/slugged.rb +1 -1
- data/test/{active_record2 → acktive_record}/slugged_status_test.rb +1 -1
- data/test/{active_record2 → acktive_record}/sti_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/support/database.mysql.yml +0 -0
- data/test/{active_record2 → acktive_record}/support/database.postgres.yml +0 -0
- data/test/{active_record2 → acktive_record}/support/database.sqlite3.yml +0 -0
- data/test/{active_record2 → acktive_record}/support/models.rb +5 -6
- data/test/{active_record2 → acktive_record}/tasks_test.rb +1 -1
- data/test/acktive_record/temp_test.rb +32 -0
- data/test/{active_record2 → acktive_record}/test_helper.rb +4 -10
- data/test/slug_string_test.rb +5 -1
- data/test/test_helper.rb +9 -3
- metadata +48 -44
- data/lib/friendly_id/active_record2/slug.rb +0 -111
- data/test/active_record2/deprecated_test.rb +0 -23
@@ -1,5 +1,5 @@
|
|
1
1
|
module FriendlyId
|
2
|
-
module
|
2
|
+
module AcktiveRecord
|
3
3
|
module SluggedModel
|
4
4
|
|
5
5
|
module SluggedFinder
|
@@ -18,7 +18,7 @@ module FriendlyId
|
|
18
18
|
class MultipleFinder
|
19
19
|
|
20
20
|
include FriendlyId::Finders::Base
|
21
|
-
include FriendlyId::
|
21
|
+
include FriendlyId::AcktiveRecord::Finders::Multiple
|
22
22
|
include SluggedFinder
|
23
23
|
|
24
24
|
attr_reader :slugs
|
@@ -86,7 +86,7 @@ module FriendlyId
|
|
86
86
|
include SluggedFinder
|
87
87
|
|
88
88
|
def find
|
89
|
-
@result =
|
89
|
+
@result = model_class.scoped(find_options).first(options)
|
90
90
|
handle_friendly_result if friendly?
|
91
91
|
@result
|
92
92
|
rescue ::ActiveRecord::RecordNotFound => @error
|
@@ -109,7 +109,7 @@ module FriendlyId
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def raise_scoped_error
|
112
|
-
scope_message =
|
112
|
+
scope_message = scope || "expected, but none given"
|
113
113
|
message = "%s, scope: %s" % [@error.message, scope_message]
|
114
114
|
raise ::ActiveRecord::RecordNotFound, message
|
115
115
|
end
|
@@ -124,7 +124,7 @@ module FriendlyId
|
|
124
124
|
include SluggedFinder
|
125
125
|
|
126
126
|
def find
|
127
|
-
@result =
|
127
|
+
@result = model_class.scoped(find_options).first(options)
|
128
128
|
handle_friendly_result if friendly?
|
129
129
|
@result
|
130
130
|
rescue ActiveRecord::RecordNotFound
|
@@ -138,81 +138,6 @@ module FriendlyId
|
|
138
138
|
|
139
139
|
end
|
140
140
|
|
141
|
-
# The methods in this module override ActiveRecord's +find_one+ and
|
142
|
-
# +find_some+ to add FriendlyId's features.
|
143
|
-
module FinderMethods
|
144
|
-
|
145
|
-
protected
|
146
|
-
|
147
|
-
def find_one(id_or_name, options)
|
148
|
-
finder = Finders::FinderProxy.new(id_or_name, self, options)
|
149
|
-
finder.unfriendly? ? super : finder.find or super
|
150
|
-
end
|
151
|
-
|
152
|
-
def find_some(ids_and_names, options)
|
153
|
-
Finders::FinderProxy.new(ids_and_names, self, options).find
|
154
|
-
end
|
155
|
-
|
156
|
-
# Since Rails goes out of its way to make these options completely
|
157
|
-
# inaccessible, we have to copy them here.
|
158
|
-
def validate_find_options(options)
|
159
|
-
options.assert_valid_keys([:conditions, :include, :joins, :limit, :offset,
|
160
|
-
:order, :select, :readonly, :group, :from, :lock, :having, :scope])
|
161
|
-
end
|
162
|
-
|
163
|
-
end
|
164
|
-
|
165
|
-
# These methods will be removed in FriendlyId 3.0.
|
166
|
-
module DeprecatedMethods
|
167
|
-
|
168
|
-
# @deprecated Please use #to_param
|
169
|
-
def best_id
|
170
|
-
warn("best_id is deprecated and will be removed in 3.0. Please use #to_param.")
|
171
|
-
to_param
|
172
|
-
end
|
173
|
-
|
174
|
-
# @deprecated Please use #friendly_id_status.slug.
|
175
|
-
def finder_slug
|
176
|
-
warn("finder_slug is deprecated and will be removed in 3.0. Please use #friendly_id_status.slug.")
|
177
|
-
friendly_id_status.slug
|
178
|
-
end
|
179
|
-
|
180
|
-
# Was the record found using one of its friendly ids?
|
181
|
-
# @deprecated Please use #friendly_id_status.friendly?
|
182
|
-
def found_using_friendly_id?
|
183
|
-
warn("found_using_friendly_id? is deprecated and will be removed in 3.0. Please use #friendly_id_status.friendly?")
|
184
|
-
friendly_id_status.friendly?
|
185
|
-
end
|
186
|
-
|
187
|
-
# Was the record found using its numeric id?
|
188
|
-
# @deprecated Please use #friendly_id_status.numeric?
|
189
|
-
def found_using_numeric_id?
|
190
|
-
warn("found_using_numeric_id is deprecated and will be removed in 3.0. Please use #friendly_id_status.numeric?")
|
191
|
-
friendly_id_status.numeric?
|
192
|
-
end
|
193
|
-
|
194
|
-
# Was the record found using an old friendly id?
|
195
|
-
# @deprecated Please use #friendly_id_status.outdated?
|
196
|
-
def found_using_outdated_friendly_id?
|
197
|
-
warn("found_using_outdated_friendly_id is deprecated and will be removed in 3.0. Please use #friendly_id_status.outdated?")
|
198
|
-
friendly_id_status.outdated?
|
199
|
-
end
|
200
|
-
|
201
|
-
# Was the record found using an old friendly id, or its numeric id?
|
202
|
-
# @deprecated Please use !#friendly_id_status.best?
|
203
|
-
def has_better_id?
|
204
|
-
warn("has_better_id? is deprecated and will be removed in 3.0. Please use !#friendly_id_status.best?")
|
205
|
-
! friendly_id_status.best?
|
206
|
-
end
|
207
|
-
|
208
|
-
# @deprecated Please use #slug?
|
209
|
-
def has_a_slug?
|
210
|
-
warn("has_a_slug? is deprecated and will be removed in 3.0. Please use #slug?")
|
211
|
-
slug?
|
212
|
-
end
|
213
|
-
|
214
|
-
end
|
215
|
-
|
216
141
|
def self.included(base)
|
217
142
|
base.class_eval do
|
218
143
|
has_many :slugs, :order => 'id DESC', :as => :sluggable, :dependent => :destroy
|
@@ -221,18 +146,17 @@ module FriendlyId
|
|
221
146
|
after_update :update_scope
|
222
147
|
after_update :update_dependent_scopes
|
223
148
|
protect_friendly_id_attributes
|
224
|
-
extend FinderMethods
|
149
|
+
extend FriendlyId::AcktiveRecord::FinderMethods
|
225
150
|
end
|
226
151
|
end
|
227
152
|
|
228
153
|
include FriendlyId::Slugged::Model
|
229
|
-
include DeprecatedMethods
|
230
154
|
|
231
155
|
def find_slug(name, sequence)
|
232
156
|
slugs.find_by_name_and_sequence(name, sequence)
|
233
157
|
end
|
234
158
|
|
235
|
-
# The model instance's current {FriendlyId::
|
159
|
+
# The model instance's current {FriendlyId::AcktiveRecord::Slug slug}.
|
236
160
|
def slug
|
237
161
|
return @slug if new_record?
|
238
162
|
@slug ||= slugs.first(:order => "id DESC")
|
@@ -273,7 +197,7 @@ module FriendlyId
|
|
273
197
|
|
274
198
|
# Reset the cached friendly_id?
|
275
199
|
def new_cache_needed?
|
276
|
-
uses_slug_cache? && send(friendly_id_config.cache_column) != slug.to_friendly_id
|
200
|
+
uses_slug_cache? && slug? && send(friendly_id_config.cache_column) != slug.to_friendly_id
|
277
201
|
end
|
278
202
|
|
279
203
|
# Reset the cached friendly_id.
|
@@ -285,7 +209,7 @@ module FriendlyId
|
|
285
209
|
end
|
286
210
|
|
287
211
|
def update_scope
|
288
|
-
return unless scope_changed?
|
212
|
+
return unless slug && scope_changed?
|
289
213
|
slug.update_attributes :scope => send(friendly_id_config.scope).to_param
|
290
214
|
rescue ActiveRecord::StatementInvalid
|
291
215
|
slug.update_attributes :sequence => Slug.similar_to(slug).first.sequence.succ
|
@@ -26,13 +26,15 @@ module FriendlyId
|
|
26
26
|
|
27
27
|
def make_slugs
|
28
28
|
validate_uses_slugs
|
29
|
-
|
29
|
+
cond = "slugs.id IS NULL"
|
30
|
+
options = {:limit => 100, :include => :slugs, :conditions => cond, :order => "#{klass.table_name}.id ASC"}.merge(task_options || {})
|
30
31
|
while records = find(:all, options) do
|
31
32
|
break if records.size == 0
|
32
33
|
records.each do |record|
|
33
34
|
record.save!
|
34
35
|
yield(record) if block_given?
|
35
36
|
end
|
37
|
+
options[:conditions] = cond + " and #{klass.table_name}.id > #{records.last.id}"
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -45,7 +47,7 @@ module FriendlyId
|
|
45
47
|
end
|
46
48
|
|
47
49
|
def delete_old_slugs
|
48
|
-
conditions = ["created_at < ?", DateTime.now - days
|
50
|
+
conditions = ["created_at < ?", DateTime.now - days]
|
49
51
|
if klass
|
50
52
|
conditions[0] << " AND sluggable_type = ?"
|
51
53
|
conditions << klass.to_s
|
@@ -54,6 +56,7 @@ module FriendlyId
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def validate_uses_slugs
|
59
|
+
(raise "You need to pass a MODEL=<model name> argument to rake") if klass.blank?
|
57
60
|
unless friendly_id_config.use_slug?
|
58
61
|
raise "Class '%s' doesn't use slugs" % klass.to_s
|
59
62
|
end
|
@@ -2,7 +2,7 @@ namespace :friendly_id do
|
|
2
2
|
desc "Make slugs for a model."
|
3
3
|
task :make_slugs => :environment do
|
4
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]
|
5
|
+
puts "%s(%d): friendly_id set to '%s'" % [record.class.to_s, record.id, record.slug.name] if record.slug
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
@@ -1,20 +1,18 @@
|
|
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
1
|
module FriendlyId
|
9
2
|
|
10
|
-
module
|
3
|
+
module AcktiveRecord
|
4
|
+
|
5
|
+
module Compat
|
6
|
+
def self.scope_method
|
7
|
+
ActiveRecord::VERSION::STRING >= "3" ? :scope : :named_scope
|
8
|
+
end
|
9
|
+
end
|
11
10
|
|
12
11
|
include FriendlyId::Base
|
13
12
|
|
14
|
-
def has_friendly_id(method, options = {}
|
13
|
+
def has_friendly_id(method, options = {})
|
15
14
|
class_inheritable_accessor :friendly_id_config
|
16
|
-
write_inheritable_attribute :friendly_id_config, Configuration.new(self,
|
17
|
-
method, options.merge(:normalizer => block))
|
15
|
+
write_inheritable_attribute :friendly_id_config, Configuration.new(self, method, options)
|
18
16
|
if friendly_id_config.use_slug?
|
19
17
|
include SluggedModel
|
20
18
|
else
|
@@ -43,5 +41,12 @@ module FriendlyId
|
|
43
41
|
end
|
44
42
|
|
45
43
|
class ActiveRecord::Base
|
46
|
-
extend FriendlyId::
|
47
|
-
end
|
44
|
+
extend FriendlyId::AcktiveRecord
|
45
|
+
end
|
46
|
+
|
47
|
+
require File.join(File.dirname(__FILE__), "acktive_record", "configuration")
|
48
|
+
require File.join(File.dirname(__FILE__), "acktive_record", "finders")
|
49
|
+
require File.join(File.dirname(__FILE__), "acktive_record", "simple_model")
|
50
|
+
require File.join(File.dirname(__FILE__), "acktive_record", "slugged_model")
|
51
|
+
require File.join(File.dirname(__FILE__), "acktive_record", "slug")
|
52
|
+
require File.join(File.dirname(__FILE__), "acktive_record", "tasks")
|
@@ -22,6 +22,7 @@ module FriendlyId
|
|
22
22
|
class Configuration
|
23
23
|
|
24
24
|
DEFAULTS = {
|
25
|
+
:allow_nil => false,
|
25
26
|
:ascii_approximation_options => [],
|
26
27
|
:max_length => 255,
|
27
28
|
:reserved_words => ["index", "new"],
|
@@ -29,6 +30,12 @@ module FriendlyId
|
|
29
30
|
:sequence_separator => "--"
|
30
31
|
}
|
31
32
|
|
33
|
+
# Whether to allow friendly_id and/or slugs to be nil. This is not
|
34
|
+
# generally useful on its own, but may allow you greater flexibility to
|
35
|
+
# customize your application.
|
36
|
+
attr_accessor :allow_nil
|
37
|
+
alias :allow_nil? :allow_nil
|
38
|
+
|
32
39
|
# Strip diacritics from Western characters.
|
33
40
|
attr_accessor :approximate_ascii
|
34
41
|
|
@@ -47,12 +54,6 @@ module FriendlyId
|
|
47
54
|
attr_reader :method
|
48
55
|
alias :column :method
|
49
56
|
|
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
57
|
# The message shown when a reserved word is used.
|
57
58
|
# @see #reserved_words
|
58
59
|
attr_accessor :reserved_message
|
@@ -85,10 +86,8 @@ module FriendlyId
|
|
85
86
|
yield self if block_given?
|
86
87
|
end
|
87
88
|
|
88
|
-
def
|
89
|
-
|
90
|
-
warn("passing a block to has_friendly_id is deprecated and will be removed from 3.0. Please override #normalize_friendly_id.")
|
91
|
-
@normalizer = arg
|
89
|
+
def forbid_nil?
|
90
|
+
!allow_nil?
|
92
91
|
end
|
93
92
|
|
94
93
|
def reserved_words=(*words)
|
@@ -103,21 +102,7 @@ module FriendlyId
|
|
103
102
|
[method, reserved_message % word] if reserved? word
|
104
103
|
end
|
105
104
|
|
106
|
-
|
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.approximate_ascii = *args
|
118
|
-
end
|
119
|
-
|
120
|
-
%w[approximate_ascii normalizer scope strip_non_ascii use_slug].each do |method|
|
105
|
+
%w[approximate_ascii scope strip_non_ascii use_slug].each do |method|
|
121
106
|
class_eval(<<-EOM)
|
122
107
|
def #{method}?
|
123
108
|
!! #{method}
|
@@ -129,4 +114,4 @@ module FriendlyId
|
|
129
114
|
|
130
115
|
end
|
131
116
|
|
132
|
-
end
|
117
|
+
end
|
data/lib/friendly_id/finders.rb
CHANGED
@@ -14,7 +14,7 @@ module FriendlyId
|
|
14
14
|
# @return [true, false, nil]
|
15
15
|
# @see #unfriendly?
|
16
16
|
def self.friendly?(id)
|
17
|
-
if id.is_a?(Integer) or id.class.respond_to? :friendly_id_config
|
17
|
+
if id.is_a?(Integer) or id.is_a?(Symbol) or id.class.respond_to? :friendly_id_config
|
18
18
|
return false
|
19
19
|
elsif id.to_i.to_s != id.to_s
|
20
20
|
return true
|
@@ -35,7 +35,7 @@ module FriendlyId
|
|
35
35
|
self.ids = ids
|
36
36
|
self.options = options
|
37
37
|
self.model_class = model_class
|
38
|
-
self.scope = options
|
38
|
+
self.scope = options.delete :scope
|
39
39
|
end
|
40
40
|
|
41
41
|
def method_missing(*args, &block)
|
@@ -67,7 +67,9 @@ module FriendlyId
|
|
67
67
|
alias :id= :ids=
|
68
68
|
|
69
69
|
def scope=(scope)
|
70
|
-
|
70
|
+
unless scope.nil?
|
71
|
+
@scope = scope.respond_to?(:to_param) ? scope.to_param : scope.to_s
|
72
|
+
end
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
@@ -162,7 +162,7 @@ module FriendlyId
|
|
162
162
|
# whitespace characters with a single space.
|
163
163
|
# @return String
|
164
164
|
def clean!
|
165
|
-
@wrapped_string = @wrapped_string.gsub(/\A\-|\-\z/,
|
165
|
+
@wrapped_string = @wrapped_string.gsub(/\A\-|\-\z/, "").gsub(/\s+/u, " ").strip
|
166
166
|
end
|
167
167
|
|
168
168
|
# Lowercases the string. Note that this works for Unicode strings,
|
@@ -198,13 +198,9 @@ module FriendlyId
|
|
198
198
|
# @param config [FriendlyId::Configuration]
|
199
199
|
# @return String
|
200
200
|
def normalize_for!(config)
|
201
|
-
if config.
|
202
|
-
|
203
|
-
|
204
|
-
approximate_ascii! if config.approximate_ascii?
|
205
|
-
to_ascii! if config.strip_non_ascii?
|
206
|
-
normalize!
|
207
|
-
end
|
201
|
+
approximate_ascii! if config.approximate_ascii?
|
202
|
+
to_ascii! if config.strip_non_ascii?
|
203
|
+
normalize!
|
208
204
|
end
|
209
205
|
|
210
206
|
alias :normalize_utf8 :normalize rescue NoMethodError
|
@@ -231,7 +227,12 @@ module FriendlyId
|
|
231
227
|
# Delete any non-ascii characters.
|
232
228
|
# @return String
|
233
229
|
def to_ascii!
|
234
|
-
|
230
|
+
if ">= 1.9".respond_to?(:force_encoding)
|
231
|
+
@wrapped_string.encode!("ASCII", :invalid => :replace, :undef => :replace,
|
232
|
+
:replace => "")
|
233
|
+
else
|
234
|
+
@wrapped_string = tidy_bytes.normalize_utf8(:c).unpack("U*").reject {|char| char > 127}.pack("U*")
|
235
|
+
end
|
235
236
|
end
|
236
237
|
|
237
238
|
# Upper-cases the string. Note that this works for Unicode strings,
|
@@ -257,7 +258,7 @@ module FriendlyId
|
|
257
258
|
# Replaces whitespace with dashes ("-").
|
258
259
|
# @return String
|
259
260
|
def with_dashes!
|
260
|
-
@wrapped_string = @wrapped_string.gsub(/[\s\-]+/u,
|
261
|
+
@wrapped_string = @wrapped_string.gsub(/[\s\-]+/u, "-")
|
261
262
|
end
|
262
263
|
|
263
264
|
%w[approximate_ascii clean downcase word_chars normalize normalize_for to_ascii
|
data/lib/friendly_id/slugged.rb
CHANGED
@@ -55,7 +55,7 @@ module FriendlyId
|
|
55
55
|
|
56
56
|
# The friendly id.
|
57
57
|
def friendly_id
|
58
|
-
slug.to_friendly_id
|
58
|
+
slug.to_friendly_id if slug?
|
59
59
|
end
|
60
60
|
|
61
61
|
# Clean up the string before setting it as the friendly_id. You can override
|
@@ -75,8 +75,11 @@ module FriendlyId
|
|
75
75
|
|
76
76
|
# Get the processed string used as the basis of the friendly id.
|
77
77
|
def slug_text
|
78
|
-
|
79
|
-
|
78
|
+
base = send(friendly_id_config.method)
|
79
|
+
unless base.nil? && friendly_id_config.allow_nil?
|
80
|
+
text = normalize_friendly_id(SlugString.new(base))
|
81
|
+
SlugString.new(text.to_s).validate_for!(friendly_id_config).to_s
|
82
|
+
end
|
80
83
|
end
|
81
84
|
|
82
85
|
# Has the slug text changed?
|
@@ -87,7 +90,11 @@ module FriendlyId
|
|
87
90
|
# Has the basis of our friendly id changed, requiring the generation of a
|
88
91
|
# new slug?
|
89
92
|
def new_slug_needed?
|
90
|
-
|
93
|
+
if friendly_id_config.allow_nil?
|
94
|
+
(!slug? && !slug_text.blank?) || (slug? && slug_text_changed?)
|
95
|
+
else
|
96
|
+
!slug? || slug_text_changed?
|
97
|
+
end
|
91
98
|
end
|
92
99
|
|
93
100
|
end
|
data/lib/friendly_id/test.rb
CHANGED
@@ -18,7 +18,6 @@ module FriendlyId
|
|
18
18
|
|
19
19
|
def teardown
|
20
20
|
klass.send delete_all_method
|
21
|
-
# other_class.delete_all
|
22
21
|
end
|
23
22
|
|
24
23
|
def instance
|
@@ -41,6 +40,10 @@ module FriendlyId
|
|
41
40
|
raise NotImplementedError
|
42
41
|
end
|
43
42
|
|
43
|
+
def update_method
|
44
|
+
raise NotImplementedError
|
45
|
+
end
|
46
|
+
|
44
47
|
def validation_exceptions
|
45
48
|
return RuntimeError
|
46
49
|
end
|
@@ -49,7 +52,7 @@ module FriendlyId
|
|
49
52
|
assert_not_nil klass.friendly_id_config
|
50
53
|
end
|
51
54
|
|
52
|
-
test "instances should have a friendly id" do
|
55
|
+
test "instances should have a friendly id by default" do
|
53
56
|
assert_not_nil instance.friendly_id
|
54
57
|
end
|
55
58
|
|
@@ -69,6 +72,11 @@ module FriendlyId
|
|
69
72
|
assert_equal instance, klass.send(find_method, instance.id.to_s)
|
70
73
|
end
|
71
74
|
|
75
|
+
test "instances should be findable by a numeric friendly_id" do
|
76
|
+
instance = klass.send(create_method, :name => "206")
|
77
|
+
assert_equal instance, klass.send(find_method, instance.friendly_id)
|
78
|
+
end
|
79
|
+
|
72
80
|
test "creation should raise an error if the friendly_id text is reserved" do
|
73
81
|
assert_raise(*[validation_exceptions].flatten) do
|
74
82
|
klass.send(create_method, :name => "new")
|
@@ -87,12 +95,17 @@ module FriendlyId
|
|
87
95
|
end
|
88
96
|
end
|
89
97
|
|
90
|
-
test "creation should raise an error if the friendly_id text is nil" do
|
98
|
+
test "creation should raise an error if the friendly_id text is nil and allow_nil is false" do
|
91
99
|
assert_raise(*[validation_exceptions].flatten) do
|
92
100
|
klass.send(create_method, :name => nil)
|
93
101
|
end
|
94
102
|
end
|
95
103
|
|
104
|
+
test "creation should succeed if the friendly_id text is nil and allow_nil is true" do
|
105
|
+
klass.friendly_id_config.stubs(:allow_nil?).returns(true)
|
106
|
+
assert klass.send(create_method, :name => nil)
|
107
|
+
end
|
108
|
+
|
96
109
|
test "should allow the same friendly_id across models" do
|
97
110
|
other_instance = other_class.send(create_method, :name => instance.name)
|
98
111
|
assert_equal other_instance.friendly_id, instance.friendly_id
|
@@ -100,6 +113,18 @@ module FriendlyId
|
|
100
113
|
|
101
114
|
end
|
102
115
|
|
116
|
+
module Simple
|
117
|
+
|
118
|
+
test "should allow friendly_id to be nillable if allow_nil is true" do
|
119
|
+
klass.friendly_id_config.stubs(:allow_nil?).returns(true)
|
120
|
+
instance = klass.send(create_method, :name => "hello")
|
121
|
+
assert instance.friendly_id
|
122
|
+
instance.name = nil
|
123
|
+
assert instance.send(save_method)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
103
128
|
# Tests for any model that implements slugs.
|
104
129
|
module Slugged
|
105
130
|
|
@@ -152,6 +177,22 @@ module FriendlyId
|
|
152
177
|
assert_equal instance, klass.find(old_friendly_id)
|
153
178
|
end
|
154
179
|
|
180
|
+
test "should not create a slug when allow_nil is true and friendy_id text is blank" do
|
181
|
+
klass.friendly_id_config.stubs(:allow_nil?).returns(true)
|
182
|
+
instance = klass.send(create_method, :name => nil)
|
183
|
+
assert_nil instance.slug
|
184
|
+
end
|
185
|
+
|
186
|
+
test "should not allow friendly_id to be nillable even if allow_nil is true" do
|
187
|
+
klass.friendly_id_config.stubs(:allow_nil?).returns(true)
|
188
|
+
instance = klass.send(create_method, :name => "hello")
|
189
|
+
assert instance.friendly_id
|
190
|
+
instance.name = nil
|
191
|
+
assert_raise(*[validation_exceptions].flatten) do
|
192
|
+
instance.send(save_method)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
155
196
|
end
|
156
197
|
|
157
198
|
# Tests for FriendlyId::Status.
|
@@ -164,7 +205,7 @@ module FriendlyId
|
|
164
205
|
assert status.numeric?
|
165
206
|
end
|
166
207
|
end
|
167
|
-
|
208
|
+
|
168
209
|
# Tests for FriendlyId::Status for a model that uses slugs.
|
169
210
|
module SluggedStatus
|
170
211
|
|
@@ -244,4 +285,4 @@ module FriendlyId
|
|
244
285
|
|
245
286
|
end
|
246
287
|
end
|
247
|
-
end
|
288
|
+
end
|