friendly_id 4.0.2 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,8 @@
1
1
  rvm:
2
2
  - 1.9.3
3
3
  - 1.8.7
4
- - jruby
5
- - rbx
4
+ # - jruby
5
+ # - rbx
6
6
 
7
7
  branches:
8
8
  only:
data/.yardopts CHANGED
@@ -1,3 +1,4 @@
1
1
  --files=WhatsNew.md,Changelog.md,Guide.rdoc
2
+ --private
2
3
  --protected
3
4
  --exclude lib/friendly_id/migration
@@ -6,6 +6,13 @@ suggestions, ideas and improvements to FriendlyId.
6
6
  * Table of Contents
7
7
  {:toc}
8
8
 
9
+ ## 4.0.3 (2012-03-14)
10
+
11
+ * Fix escape for '%' and '_' on SQLite (Norman Clarke and Sergey Petrunin)
12
+ * Allow FriendlyId to be extended or included (Norman Clarke)
13
+ * Allow Configuration#use to accept a Module (Norman Clarke)
14
+ * Fix bugs with History module + STI (Norman Clarke and Sergey Petrunin)
15
+
9
16
  ## 4.0.2 (2012-03-12)
10
17
 
11
18
  * Improved conflict handling and performance in History module (Erik Ogan and Thomas Shafer)
data/Guide.rdoc CHANGED
@@ -38,12 +38,13 @@ with numeric ids:
38
38
 
39
39
  == Setting Up FriendlyId in Your Model
40
40
 
41
- To use FriendlyId in your ActiveRecord models, you must first extend the
42
- FriendlyId module, then invoke the {FriendlyId::Base#friendly_id friendly_id}
43
- method to configure your desired options:
41
+ To use FriendlyId in your ActiveRecord models, you must first either extend or
42
+ include the FriendlyId module (it makes no difference), then invoke the
43
+ {FriendlyId::Base#friendly_id friendly_id} method to configure your desired
44
+ options:
44
45
 
45
46
  class Foo < ActiveRecord::Base
46
- extend FriendlyId
47
+ include FriendlyId
47
48
  friendly_id :bar, :use => [:slugged, :simple_i18n]
48
49
  end
49
50
 
@@ -401,7 +402,7 @@ an example of one way to set this up:
401
402
  http://example.org/cities/chicago/restaurants/joes-diner
402
403
 
403
404
 
404
- == Simple I18n
405
+ == Translating Slugs Using Simple I18n
405
406
 
406
407
  The {FriendlyId::SimpleI18n SimpleI18n} module adds very basic i18n support to
407
408
  FriendlyId.
@@ -409,8 +410,12 @@ FriendlyId.
409
410
  In order to use this module, your model must have a slug column for each locale.
410
411
  By default FriendlyId looks for columns named, for example, "slug_en",
411
412
  "slug_es", etc. The first part of the name can be configured by passing the
412
- +:slug_column+ option if you choose. Note that as of 4.0.0.beta11, the column
413
- for the default locale must also include the locale in its name.
413
+ +:slug_column+ option if you choose. Note that the column for the default locale
414
+ must also include the locale in its name.
415
+
416
+ This module is most suitable to applications that need to support few locales.
417
+ If you need to support two or more locales, you may wish to use the
418
+ {FriendlyId::Globalize Globalize} module instead.
414
419
 
415
420
  === Example migration
416
421
 
@@ -462,6 +467,54 @@ current locale:
462
467
  end
463
468
 
464
469
 
470
+ == Translating Slugs Using Globalize
471
+
472
+ The {FriendlyId::Globalize Globalize} module lets you use
473
+ Globalize[https://github.com/svenfuchs/globalize3] to translate slugs. This
474
+ module is most suitable for applications that need to be localized to many
475
+ languages. If your application only needs to be localized to one or two
476
+ languages, you may wish to consider the {FriendlyId::SimpleI18n SimpleI18n}
477
+ module.
478
+
479
+ In order to use this module, your model must have a slug column and set the
480
+ field +slug+ as translable with Globalize:
481
+
482
+ class Post < ActiveRecord::Base
483
+ translates :title, :slug
484
+ extend FriendlyId
485
+ friendly_id :title, :use => :globalize
486
+ end
487
+
488
+ === Finds
489
+
490
+ Finds will take the current locale into consideration:
491
+
492
+ I18n.locale = :it
493
+ Post.find("guerre-stellari")
494
+ I18n.locale = :en
495
+ Post.find("star-wars")
496
+
497
+ To find a slug by an explicit locale, perform the find inside a block
498
+ passed to I18n's +with_locale+ method:
499
+
500
+ I18n.with_locale(:it) do
501
+ Post.find("guerre-stellari")
502
+ end
503
+
504
+ === Creating Records
505
+
506
+ When new records are created, the slug is generated for the current locale only.
507
+
508
+ === Translating Slugs
509
+
510
+ To translate an existing record's friendly_id, simply change the locale and
511
+ assign a value to the +slug+ field:
512
+
513
+ I18n.with_locale(:it) do
514
+ post.slug = "guerre-stellari"
515
+ end
516
+
517
+
465
518
  == Reserved Words
466
519
 
467
520
  The {FriendlyId::Reserved Reserved} module adds the ability to exlude a list of
data/Rakefile CHANGED
@@ -3,7 +3,14 @@ require "rake/testtask"
3
3
 
4
4
  task :default => :test
5
5
 
6
+ task :load_path do
7
+ %w(lib test).each do |path|
8
+ $LOAD_PATH.unshift(File.expand_path("../#{path}", __FILE__))
9
+ end
10
+ end
11
+
6
12
  Rake::TestTask.new do |t|
13
+ t.libs << "test"
7
14
  t.test_files = FileList['test/*_test.rb']
8
15
  t.verbose = true
9
16
  end
@@ -21,7 +28,7 @@ task :yard => :guide do
21
28
  puts %x{bundle exec yard}
22
29
  end
23
30
 
24
- task :bench do
31
+ task :bench => :load_path do
25
32
  require File.expand_path("../bench", __FILE__)
26
33
  end
27
34
 
@@ -40,6 +47,7 @@ task :guide do
40
47
  buffer << read_comments("lib/friendly_id/history.rb")
41
48
  buffer << read_comments("lib/friendly_id/scoped.rb")
42
49
  buffer << read_comments("lib/friendly_id/simple_i18n.rb")
50
+ buffer << read_comments("lib/friendly_id/globalize.rb")
43
51
  buffer << read_comments("lib/friendly_id/reserved.rb")
44
52
 
45
53
  File.open("Guide.rdoc", "w") do |file|
@@ -55,7 +63,7 @@ namespace :test do
55
63
  dir = File.expand_path("../test", __FILE__)
56
64
  Dir["#{dir}/*_test.rb"].each do |test|
57
65
  puts "Running #{test}:"
58
- puts %x{ruby #{test}}
66
+ puts %x{ruby -Ilib -Itest #{test}}
59
67
  end
60
68
  end
61
69
  end
@@ -63,8 +71,8 @@ end
63
71
  namespace :db do
64
72
 
65
73
  desc "Create the database"
66
- task :create do
67
- require File.expand_path("../test/helper", __FILE__)
74
+ task :create => :load_path do
75
+ require "helper"
68
76
  driver = FriendlyId::Test::Database.driver
69
77
  config = FriendlyId::Test::Database.config[driver]
70
78
  commands = {
@@ -75,8 +83,8 @@ namespace :db do
75
83
  end
76
84
 
77
85
  desc "Create the database"
78
- task :drop do
79
- require File.expand_path("../test/helper", __FILE__)
86
+ task :drop => :load_path do
87
+ require "helper"
80
88
  driver = FriendlyId::Test::Database.driver
81
89
  config = FriendlyId::Test::Database.config[driver]
82
90
  commands = {
@@ -87,8 +95,8 @@ namespace :db do
87
95
  end
88
96
 
89
97
  desc "Set up the database schema"
90
- task :up do
91
- require File.expand_path("../test/helper", __FILE__)
98
+ task :up => :load_path do
99
+ require "helper"
92
100
  FriendlyId::Test::Schema.up
93
101
  end
94
102
 
@@ -45,7 +45,7 @@ with numeric ids:
45
45
  module FriendlyId
46
46
 
47
47
  # The current version.
48
- VERSION = "4.0.2"
48
+ VERSION = "4.0.3"
49
49
 
50
50
  @mutex = Mutex.new
51
51
 
@@ -90,6 +90,11 @@ module FriendlyId
90
90
  end
91
91
  end
92
92
 
93
+ # Allow developers to `include` FriendlyId or `extend` it.
94
+ def self.included(model_class)
95
+ model_class.extend self
96
+ end
97
+
93
98
  # Set global defaults for all models using FriendlyId.
94
99
  #
95
100
  # The default defaults are to use the +:reserved+ module and nothing else.
@@ -3,12 +3,13 @@ module FriendlyId
3
3
 
4
4
  == Setting Up FriendlyId in Your Model
5
5
 
6
- To use FriendlyId in your ActiveRecord models, you must first extend the
7
- FriendlyId module, then invoke the {FriendlyId::Base#friendly_id friendly_id}
8
- method to configure your desired options:
6
+ To use FriendlyId in your ActiveRecord models, you must first either extend or
7
+ include the FriendlyId module (it makes no difference), then invoke the
8
+ {FriendlyId::Base#friendly_id friendly_id} method to configure your desired
9
+ options:
9
10
 
10
11
  class Foo < ActiveRecord::Base
11
- extend FriendlyId
12
+ include FriendlyId
12
13
  friendly_id :bar, :use => [:slugged, :simple_i18n]
13
14
  end
14
15
 
@@ -129,10 +130,34 @@ often better and easier to use {FriendlyId::Slugged slugs}.
129
130
  # end
130
131
  # end
131
132
  #
132
- # @option options [Symbol] :use The name of an addon to use. By default,
133
- # FriendlyId provides {FriendlyId::Slugged :slugged},
133
+ # === Including Your Own Modules
134
+ #
135
+ # Because :use can accept a name or a Module, {FriendlyId.defaults defaults}
136
+ # can be a convenient place to set up behavior common to all classes using
137
+ # FriendlyId. You can include any module, or more conveniently, define one
138
+ # on-the-fly. For example, let's say you want to make
139
+ # Babosa[http://github.com/norman/babosa] the default slugging library in
140
+ # place of Active Support, and transliterate all slugs from Russian Cyrillic
141
+ # to ASCII:
142
+ #
143
+ # require "babosa"
144
+ #
145
+ # FriendlyId.defaults do |config|
146
+ # config.base = :name
147
+ # config.use :slugged
148
+ # config.use Module.new {
149
+ # def normalize_friendly_id(text)
150
+ # text.to_slug.normalize(:transliterations => [:russian, :latin])
151
+ # end
152
+ # }
153
+ # end
154
+ #
155
+ #
156
+ # @option options [Symbol,Module] :use The addon or name of an addon to use.
157
+ # By default, FriendlyId provides {FriendlyId::Slugged :slugged},
134
158
  # {FriendlyId::History :history}, {FriendlyId::Reserved :reserved}, and
135
- # {FriendlyId::Scoped :scoped}.
159
+ # {FriendlyId::Scoped :scoped}, {FriendlyId::SimpleI18n :simple_i18n},
160
+ # and {FriendlyId::Globalize :globalize}.
136
161
  #
137
162
  # @option options [Array] :reserved_words Available when using +:reserved+,
138
163
  # which is loaded by default. Sets an array of words banned for use as
@@ -161,21 +186,24 @@ often better and easier to use {FriendlyId::Slugged slugs}.
161
186
  #
162
187
  # @yieldparam config The model class's {FriendlyId::Configuration friendly_id_config}.
163
188
  def friendly_id(base = nil, options = {}, &block)
164
- yield @friendly_id_config if block_given?
165
- @friendly_id_config.use options.delete :use
166
- @friendly_id_config.send :set, base ? options.merge(:base => base) : options
189
+ yield friendly_id_config if block_given?
190
+ friendly_id_config.use options.delete :use
191
+ friendly_id_config.send :set, base ? options.merge(:base => base) : options
167
192
  before_save {|rec| rec.instance_eval {@current_friendly_id = friendly_id}}
168
193
  include Model
169
194
  end
170
195
 
171
196
  # Returns the model class's {FriendlyId::Configuration friendly_id_config}.
172
197
  # @note In the case of Single Table Inheritance (STI), this method will
173
- # duplicate the parent class's FriendlyId::Configuration instance on first
174
- # access. If you're concerned about thread safety, then be sure to invoke
175
- # {#friendly_id} in your class for each model.
198
+ # duplicate the parent class's FriendlyId::Configuration and relation class
199
+ # on first access. If you're concerned about thread safety, then be sure
200
+ # to invoke {#friendly_id} in your class for each model.
176
201
  def friendly_id_config
177
202
  @friendly_id_config or begin
178
- @friendly_id_config = base_class.friendly_id_config.dup
203
+ @friendly_id_config = base_class.friendly_id_config.dup.tap do |config|
204
+ config.model_class = self
205
+ @relation_class = base_class.send(:relation_class)
206
+ end
179
207
  end
180
208
  end
181
209
 
@@ -32,7 +32,7 @@ module FriendlyId
32
32
 
33
33
  # The model class that this configuration belongs to.
34
34
  # @return ActiveRecord::Base
35
- attr_reader :model_class
35
+ attr_accessor :model_class
36
36
 
37
37
  def initialize(model_class, values = nil)
38
38
  @model_class = model_class
@@ -51,13 +51,14 @@ module FriendlyId
51
51
  # extend FriendlyId
52
52
  # friendly_id :name, :use => :slugged
53
53
  # end
54
- # @param [#to_s] *modules Arguments should be a symbols or strings that
55
- # correspond with the name of a module inside the FriendlyId namespace. By
56
- # default FriendlyId provides +:slugged+, +:history+, +:simple_i18n+ and +:scoped+.
54
+ # @param [#to_s,Module] *modules Arguments should be Modules, or symbols or
55
+ # strings that correspond with the name of a module inside the FriendlyId
56
+ # namespace. By default FriendlyId provides +:slugged+, +:history+,
57
+ # +:simple_i18n+, +:globalize+, and +:scoped+.
57
58
  def use(*modules)
58
- modules.to_a.flatten.compact.map do |name|
59
- mod = FriendlyId.const_get(name.to_s.classify)
60
- model_class.send(:include, mod) unless model_class < mod
59
+ modules.to_a.flatten.compact.map do |object|
60
+ mod = object.kind_of?(Module) ? object : FriendlyId.const_get(object.to_s.classify)
61
+ model_class.send(:include, mod)
61
62
  end
62
63
  end
63
64
 
@@ -4,13 +4,17 @@ module FriendlyId
4
4
 
5
5
  =begin
6
6
 
7
- == Translate slug db column using Globalize
7
+ == Translating Slugs Using Globalize
8
8
 
9
- The {FriendlyId::Globalize Globalize} module allow to use
10
- Globalize (https://github.com/svenfuchs/globalize3) to translate slugs.
9
+ The {FriendlyId::Globalize Globalize} module lets you use
10
+ Globalize[https://github.com/svenfuchs/globalize3] to translate slugs. This
11
+ module is most suitable for applications that need to be localized to many
12
+ languages. If your application only needs to be localized to one or two
13
+ languages, you may wish to consider the {FriendlyId::SimpleI18n SimpleI18n}
14
+ module.
11
15
 
12
16
  In order to use this module, your model must have a slug column and set the
13
- field +slug+ translable with Globalize:
17
+ field +slug+ as translable with Globalize:
14
18
 
15
19
  class Post < ActiveRecord::Base
16
20
  translates :title, :slug
@@ -20,7 +24,7 @@ field +slug+ translable with Globalize:
20
24
 
21
25
  === Finds
22
26
 
23
- Finds will take into consideration the current locale:
27
+ Finds will take the current locale into consideration:
24
28
 
25
29
  I18n.locale = :it
26
30
  Post.find("guerre-stellari")
@@ -40,8 +44,8 @@ When new records are created, the slug is generated for the current locale only.
40
44
 
41
45
  === Translating Slugs
42
46
 
43
- To translate an existing record's friendly_id, simply change locale and assign
44
- +slug+ field:
47
+ To translate an existing record's friendly_id, simply change the locale and
48
+ assign a value to the +slug+ field:
45
49
 
46
50
  I18n.with_locale(:it) do
47
51
  post.slug = "guerre-stellari"
@@ -74,12 +74,15 @@ method.
74
74
  private
75
75
 
76
76
  def create_slug
77
+ return unless friendly_id
77
78
  return if slugs.first.try(:slug) == friendly_id
78
79
  # Allow reversion back to a previously used slug
79
80
  relation = slugs.where(:slug => friendly_id)
80
81
  result = relation.select("id").lock(true).all
81
82
  relation.delete_all unless result.empty?
82
- slugs.create! :slug => friendly_id
83
+ slugs.create! do |record|
84
+ record.slug = friendly_id
85
+ end
83
86
  end
84
87
 
85
88
  # Adds a finder that explictly uses slugs from the slug table.
@@ -106,7 +109,7 @@ method.
106
109
  # Accepts a slug, and yields a corresponding sluggable_id into the block.
107
110
  def with_old_friendly_id(slug, &block)
108
111
  sql = "SELECT sluggable_id FROM #{Slug.quoted_table_name} WHERE sluggable_type = %s AND slug = %s"
109
- sql = sql % [@klass.base_class.name, slug].map {|x| connection.quote(x)}
112
+ sql = sql % [@klass.base_class.to_s, slug].map {|x| connection.quote(x)}
110
113
  sluggable_id = connection.select_values(sql).first
111
114
  yield sluggable_id if sluggable_id
112
115
  end
@@ -117,17 +120,14 @@ method.
117
120
  module SlugGenerator
118
121
 
119
122
  private
120
- def last_in_sequence
121
- @_last_in_sequence ||= extract_sequence_from_slug(conflict.slug)
122
- end
123
123
 
124
124
  def conflicts
125
- sluggable_class = friendly_id_config.model_class
125
+ sluggable_class = friendly_id_config.model_class.base_class
126
126
  pkey = sluggable_class.primary_key
127
127
  value = sluggable.send pkey
128
128
 
129
129
  scope = Slug.where("slug = ? OR slug LIKE ?", normalized, wildcard)
130
- scope = scope.where(:sluggable_type => sluggable_class.name)
130
+ scope = scope.where(:sluggable_type => sluggable_class.to_s)
131
131
  scope = scope.where("sluggable_id <> ?", value) unless sluggable.new_record?
132
132
  scope.order("LENGTH(slug) DESC, slug DESC")
133
133
  end
@@ -4,7 +4,7 @@ module FriendlyId
4
4
 
5
5
  =begin
6
6
 
7
- == Simple I18n
7
+ == Translating Slugs Using Simple I18n
8
8
 
9
9
  The {FriendlyId::SimpleI18n SimpleI18n} module adds very basic i18n support to
10
10
  FriendlyId.
@@ -12,8 +12,12 @@ FriendlyId.
12
12
  In order to use this module, your model must have a slug column for each locale.
13
13
  By default FriendlyId looks for columns named, for example, "slug_en",
14
14
  "slug_es", etc. The first part of the name can be configured by passing the
15
- +:slug_column+ option if you choose. Note that as of 4.0.0.beta11, the column
16
- for the default locale must also include the locale in its name.
15
+ +:slug_column+ option if you choose. Note that the column for the default locale
16
+ must also include the locale in its name.
17
+
18
+ This module is most suitable to applications that need to support few locales.
19
+ If you need to support two or more locales, you may wish to use the
20
+ {FriendlyId::Globalize Globalize} module instead.
17
21
 
18
22
  === Example migration
19
23
 
@@ -5,5 +5,10 @@ module FriendlyId
5
5
  class Slug < ActiveRecord::Base
6
6
  self.table_name = "friendly_id_slugs"
7
7
  belongs_to :sluggable, :polymorphic => true
8
+
9
+ def to_param
10
+ slug
11
+ end
12
+
8
13
  end
9
14
  end
@@ -51,11 +51,14 @@ module FriendlyId
51
51
  end
52
52
 
53
53
  def conflicts
54
- sluggable_class = friendly_id_config.model_class
54
+ sluggable_class = friendly_id_config.model_class.base_class
55
55
 
56
56
  pkey = sluggable_class.primary_key
57
57
  value = sluggable.send pkey
58
- scope = sluggable_class.unscoped.where("#{column} = ? OR #{column} LIKE ?", normalized, wildcard)
58
+ base = "#{column} = ? OR #{column} LIKE ?"
59
+ # Awful hack for SQLite3, which does not pick up '\' as the escape character without this.
60
+ base << "ESCAPE '\\'" if sluggable.connection.adapter_name =~ /sqlite/i
61
+ scope = sluggable_class.unscoped.where(base, normalized, wildcard)
59
62
  scope = scope.where("#{pkey} <> ?", value) unless sluggable.new_record?
60
63
  scope = scope.order("LENGTH(#{column}) DESC, #{column} DESC")
61
64
  end
@@ -1,8 +1,22 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class CoreTest < MiniTest::Unit::TestCase
4
4
  include FriendlyId::Test
5
5
 
6
+ test "friendly_id can be added using 'extend'" do
7
+ klass = Class.new(ActiveRecord::Base) do
8
+ extend FriendlyId
9
+ end
10
+ assert klass.respond_to? :friendly_id
11
+ end
12
+
13
+ test "friendly_id can be added using 'include'" do
14
+ klass = Class.new(ActiveRecord::Base) do
15
+ include FriendlyId
16
+ end
17
+ assert klass.respond_to? :friendly_id
18
+ end
19
+
6
20
  test "friendly_id should accept a base and a hash" do
7
21
  klass = Class.new(ActiveRecord::Base) do
8
22
  self.abstract_class = true
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class ConfigurationTest < MiniTest::Unit::TestCase
4
4
 
@@ -26,4 +26,23 @@ class ConfigurationTest < MiniTest::Unit::TestCase
26
26
  end
27
27
  end
28
28
 
29
+ test "#use should accept a name that resolves to a module" do
30
+ refute @model_class < FriendlyId::Slugged
31
+ @model_class.class_eval do
32
+ extend FriendlyId
33
+ friendly_id :hello, :use => :slugged
34
+ end
35
+ assert @model_class < FriendlyId::Slugged
36
+ end
37
+
38
+ test "#use should accept a module" do
39
+ my_module = Module.new
40
+ refute @model_class < my_module
41
+ @model_class.class_eval do
42
+ extend FriendlyId
43
+ friendly_id :hello, :use => my_module
44
+ end
45
+ assert @model_class < my_module
46
+ end
47
+
29
48
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class Author < ActiveRecord::Base
4
4
  extend FriendlyId
@@ -1,5 +1,4 @@
1
- require File.expand_path("../helper", __FILE__)
2
-
1
+ require "helper"
3
2
  require "rails/generators"
4
3
  require "generators/friendly_id_generator"
5
4
 
@@ -1,7 +1,3 @@
1
- $: << File.expand_path("../../lib", __FILE__)
2
- $: << File.expand_path("../", __FILE__)
3
- $:.uniq!
4
-
5
1
  require "rubygems"
6
2
  require "bundler/setup"
7
3
  require "mocha"
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class Manual < ActiveRecord::Base
4
4
  extend FriendlyId
@@ -133,3 +133,17 @@ class HistoryTest < MiniTest::Unit::TestCase
133
133
  end
134
134
 
135
135
  end
136
+
137
+ class HistoryTestWithSti < HistoryTest
138
+ class Journalist < ActiveRecord::Base
139
+ extend FriendlyId
140
+ friendly_id :name, :use => [:slugged, :history]
141
+ end
142
+
143
+ class Editorialist < Journalist
144
+ end
145
+
146
+ def model_class
147
+ Editorialist
148
+ end
149
+ end
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class I18nTest < MiniTest::Unit::TestCase
4
4
  include FriendlyId::Test
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require "helper"
2
2
 
3
3
 
4
4
  class ObjectUtilsTest < MiniTest::Unit::TestCase
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class ReservedTest < MiniTest::Unit::TestCase
4
4
 
@@ -32,6 +32,7 @@ module FriendlyId
32
32
  add_column :novels, :novelist_id, :integer
33
33
  add_column :novels, :publisher_id, :integer
34
34
  remove_index :novels, :slug
35
+ add_index :novels, [:slug, :publisher_id, :novelist_id], :unique => true
35
36
 
36
37
  # This will be used to test column name quoting
37
38
  add_column :journalists, "strange name", :string
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class Novelist < ActiveRecord::Base
4
4
  extend FriendlyId
@@ -46,7 +46,7 @@ module FriendlyId
46
46
  record.slug = nil
47
47
  record.save!
48
48
  assert_nil record.slug
49
- record.save
49
+ record.save!
50
50
  refute_nil record.slug
51
51
  end
52
52
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class Journalist < ActiveRecord::Base
4
4
  extend FriendlyId
@@ -202,6 +202,26 @@ class SluggedRegressionsTest < MiniTest::Unit::TestCase
202
202
  end
203
203
  end
204
204
 
205
+ class UnderscoreAsSequenceSeparatorRegressionTest < MiniTest::Unit::TestCase
206
+ include FriendlyId::Test
207
+
208
+ class Manual < ActiveRecord::Base
209
+ extend FriendlyId
210
+ friendly_id :name, :use => :slugged, :sequence_separator => "_"
211
+ end
212
+
213
+ test "should not create duplicate slugs" do
214
+ 3.times do
215
+ begin
216
+ assert Manual.create! :name => "foo"
217
+ rescue
218
+ flunk "Tried to insert duplicate slug"
219
+ end
220
+ end
221
+ end
222
+
223
+ end
224
+
205
225
  # https://github.com/norman/friendly_id/issues/148
206
226
  class FailedValidationAfterUpdateRegressionTest < MiniTest::Unit::TestCase
207
227
  include FriendlyId::Test
@@ -1,4 +1,4 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require "helper"
2
2
 
3
3
  class StiTest < MiniTest::Unit::TestCase
4
4
 
@@ -30,6 +30,10 @@ class StiTest < MiniTest::Unit::TestCase
30
30
  assert_equal :bar, klass.friendly_id_config.slug_column
31
31
  end
32
32
 
33
+ test "the configuration's model_class should be the class, not the base_class" do
34
+ assert_equal model_class, model_class.friendly_id_config.model_class
35
+ end
36
+
33
37
  test "friendly_id should accept a block with single table inheritance" do
34
38
  abstract_klass = Class.new(ActiveRecord::Base) do
35
39
  def self.table_exists?; false end
@@ -47,11 +51,27 @@ class StiTest < MiniTest::Unit::TestCase
47
51
  end
48
52
 
49
53
  test "friendly_id slugs should not clash with eachother" do
50
- journalist = Journalist.create! :name => 'foo bar'
51
- editoralist = Editorialist.create! :name => 'foo bar'
54
+ transaction do
55
+ journalist = model_class.base_class.create! :name => 'foo bar'
56
+ editoralist = model_class.create! :name => 'foo bar'
52
57
 
53
- assert_equal 'foo-bar', journalist.slug
54
- assert_equal 'foo-bar--2', editoralist.slug
58
+ assert_equal 'foo-bar', journalist.slug
59
+ assert_equal 'foo-bar--2', editoralist.slug
60
+ end
55
61
  end
56
62
 
57
63
  end
64
+
65
+ class StiTestWithHistory < StiTest
66
+ class Journalist < ActiveRecord::Base
67
+ extend FriendlyId
68
+ friendly_id :name, :use => [:slugged, :history]
69
+ end
70
+
71
+ class Editorialist < Journalist
72
+ end
73
+
74
+ def model_class
75
+ Editorialist
76
+ end
77
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friendly_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.2
4
+ version: 4.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-12 00:00:00.000000000 Z
12
+ date: 2012-03-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
16
- requirement: &70322875898160 !ruby/object:Gem::Requirement
16
+ requirement: &70135168764860 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.2.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70322875898160
24
+ version_requirements: *70135168764860
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activerecord
27
- requirement: &70322875893740 !ruby/object:Gem::Requirement
27
+ requirement: &70135168764100 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 3.2.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70322875893740
35
+ version_requirements: *70135168764100
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: minitest
38
- requirement: &70322875889580 !ruby/object:Gem::Requirement
38
+ requirement: &70135168763460 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70322875889580
46
+ version_requirements: *70135168763460
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: mocha
49
- requirement: &70322875886660 !ruby/object:Gem::Requirement
49
+ requirement: &70135171790060 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70322875886660
57
+ version_requirements: *70135171790060
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: maruku
60
- requirement: &70322875883700 !ruby/object:Gem::Requirement
60
+ requirement: &70135171789640 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70322875883700
68
+ version_requirements: *70135171789640
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: yard
71
- requirement: &70322875857480 !ruby/object:Gem::Requirement
71
+ requirement: &70135171789220 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70322875857480
79
+ version_requirements: *70135171789220
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: i18n
82
- requirement: &70322875830720 !ruby/object:Gem::Requirement
82
+ requirement: &70135171788800 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70322875830720
90
+ version_requirements: *70135171788800
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: ffaker
93
- requirement: &70322875828040 !ruby/object:Gem::Requirement
93
+ requirement: &70135171788380 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70322875828040
101
+ version_requirements: *70135171788380
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: simplecov
104
- requirement: &70322875809660 !ruby/object:Gem::Requirement
104
+ requirement: &70135171787960 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,7 +109,7 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70322875809660
112
+ version_requirements: *70135171787960
113
113
  description: ! 'FriendlyId is the "Swiss Army bulldozer" of slugging and permalink
114
114
  plugins for
115
115