friendly_id 2.3.4 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|