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.
Files changed (47) hide show
  1. data/Changelog.md +10 -0
  2. data/Contributors.md +1 -0
  3. data/Guide.md +48 -4
  4. data/README.md +6 -4
  5. data/Rakefile +1 -1
  6. data/extras/extras.rb +1 -1
  7. data/generators/friendly_id/friendly_id_generator.rb +1 -1
  8. data/lib/friendly_id.rb +4 -6
  9. data/lib/friendly_id/{active_record2 → acktive_record}/configuration.rb +2 -2
  10. data/lib/friendly_id/{active_record2 → acktive_record}/finders.rb +24 -10
  11. data/lib/friendly_id/{active_record2 → acktive_record}/simple_model.rb +12 -50
  12. data/lib/friendly_id/acktive_record/slug.rb +66 -0
  13. data/lib/friendly_id/{active_record2 → acktive_record}/slugged_model.rb +9 -85
  14. data/lib/friendly_id/{active_record2 → acktive_record}/tasks.rb +5 -2
  15. data/lib/friendly_id/{active_record2 → acktive_record}/tasks/friendly_id.rake +1 -1
  16. data/lib/friendly_id/{active_record2.rb → active_record.rb} +18 -13
  17. data/lib/friendly_id/configuration.rb +11 -26
  18. data/lib/friendly_id/finders.rb +5 -3
  19. data/lib/friendly_id/slug_string.rb +11 -10
  20. data/lib/friendly_id/slugged.rb +11 -4
  21. data/lib/friendly_id/test.rb +46 -5
  22. data/lib/friendly_id/version.rb +5 -4
  23. data/lib/generators/friendly_id_generator.rb +32 -0
  24. data/rails/init.rb +1 -1
  25. data/test/{active_record2 → acktive_record}/basic_slugged_model_test.rb +3 -3
  26. data/test/{active_record2 → acktive_record}/cached_slug_test.rb +3 -3
  27. data/test/{active_record2 → acktive_record}/core.rb +1 -1
  28. data/test/{active_record2 → acktive_record}/custom_normalizer_test.rb +3 -3
  29. data/test/{active_record2 → acktive_record}/custom_table_name_test.rb +3 -3
  30. data/test/{active_record2 → acktive_record}/scoped_model_test.rb +2 -2
  31. data/test/{active_record2 → acktive_record}/simple_test.rb +4 -1
  32. data/test/{active_record2 → acktive_record}/slug_test.rb +0 -0
  33. data/test/{active_record2 → acktive_record}/slugged.rb +1 -1
  34. data/test/{active_record2 → acktive_record}/slugged_status_test.rb +1 -1
  35. data/test/{active_record2 → acktive_record}/sti_test.rb +3 -3
  36. data/test/{active_record2 → acktive_record}/support/database.mysql.yml +0 -0
  37. data/test/{active_record2 → acktive_record}/support/database.postgres.yml +0 -0
  38. data/test/{active_record2 → acktive_record}/support/database.sqlite3.yml +0 -0
  39. data/test/{active_record2 → acktive_record}/support/models.rb +5 -6
  40. data/test/{active_record2 → acktive_record}/tasks_test.rb +1 -1
  41. data/test/acktive_record/temp_test.rb +32 -0
  42. data/test/{active_record2 → acktive_record}/test_helper.rb +4 -10
  43. data/test/slug_string_test.rb +5 -1
  44. data/test/test_helper.rb +9 -3
  45. metadata +48 -44
  46. data/lib/friendly_id/active_record2/slug.rb +0 -111
  47. data/test/active_record2/deprecated_test.rb +0 -23
@@ -1,5 +1,5 @@
1
1
  module FriendlyId
2
- module ActiveRecord2
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::ActiveRecord2::Finders::Multiple
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 = with_scope({:find => find_options}) { find_initial options }
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 = options[:scope] || "expected, but none given"
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 = with_scope({:find => find_options}) { find_initial options }
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::ActiveRecord2::Slug slug}.
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
- options = {:limit => 100, :include => :slugs, :conditions => "slugs.id IS NULL"}.merge(task_options || {})
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.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 ActiveRecord2
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 = {}, &block)
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::ActiveRecord2
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 normalizer=(arg)
89
- return if arg.nil?
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
- # 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.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
@@ -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[:scope]
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
- @scope = scope.to_param unless scope.nil?
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/, '').gsub(/\s+/u, ' ').strip
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.normalizer?
202
- @wrapped_string = config.normalizer.call(to_s)
203
- else
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
- @wrapped_string = normalize_utf8(:c).unpack("U*").reject {|char| char > 127}.pack("U*")
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
@@ -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
- text = normalize_friendly_id(SlugString.new(send(friendly_id_config.method)))
79
- SlugString.new(text.to_s).validate_for!(friendly_id_config).to_s
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
- !slug? || slug_text_changed?
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
@@ -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