friendly_id 2.2.5 → 2.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,6 @@
1
- # encoding: utf-8
2
-
3
1
  require File.dirname(__FILE__) + '/test_helper'
4
2
 
3
+
5
4
  class ScopedModelTest < Test::Unit::TestCase
6
5
 
7
6
  context "A slugged model that uses a scope" do
@@ -9,33 +8,42 @@ class ScopedModelTest < Test::Unit::TestCase
9
8
  setup do
10
9
  @usa = Country.create!(:name => "USA")
11
10
  @canada = Country.create!(:name => "Canada")
12
- @person = Person.create!(:name => "John Smith", :country => @usa)
13
- @person2 = Person.create!(:name => "John Smith", :country => @canada)
11
+ @resident = Resident.create!(:name => "John Smith", :country => @usa)
12
+ @resident2 = Resident.create!(:name => "John Smith", :country => @canada)
14
13
  end
15
14
 
16
15
  teardown do
17
- Person.delete_all
16
+ Resident.delete_all
18
17
  Country.delete_all
19
18
  Slug.delete_all
20
19
  end
21
20
 
21
+ should "should not show the scope in the friendly_id" do
22
+ assert_equal "john-smith", @resident.friendly_id
23
+ assert_equal "john-smith", @resident2.friendly_id
24
+ end
25
+
22
26
  should "find all scoped records without scope" do
23
- assert_equal 2, Person.find(:all, @person.friendly_id).size
27
+ assert_equal 2, Resident.find(:all, @resident.friendly_id).size
28
+ end
29
+
30
+ should "find a single scoped records with a scope as a string" do
31
+ assert Resident.find(@resident.friendly_id, :scope => @resident.country.to_param)
24
32
  end
25
33
 
26
34
  should "find a single scoped records with a scope" do
27
- assert Person.find(@person.friendly_id, :scope => @person.country.to_param)
35
+ assert Resident.find(@resident.friendly_id, :scope => @resident.country)
28
36
  end
29
37
 
30
38
  should "raise an error when finding a single scoped record with no scope" do
31
39
  assert_raises ActiveRecord::RecordNotFound do
32
- Person.find(@person.friendly_id)
40
+ Resident.find(@resident.friendly_id)
33
41
  end
34
42
  end
35
43
 
36
44
  should "append scope error info when missing scope causes a find to fail" do
37
45
  begin
38
- Person.find(@person.friendly_id)
46
+ Resident.find(@resident.friendly_id)
39
47
  fail "The find should not have succeeded"
40
48
  rescue ActiveRecord::RecordNotFound => e
41
49
  assert_match /expected scope/, e.message
@@ -44,7 +52,7 @@ class ScopedModelTest < Test::Unit::TestCase
44
52
 
45
53
  should "append scope error info when the scope value causes a find to fail" do
46
54
  begin
47
- Person.find(@person.friendly_id, :scope => "badscope")
55
+ Resident.find(@resident.friendly_id, :scope => "badscope")
48
56
  fail "The find should not have succeeded"
49
57
  rescue ActiveRecord::RecordNotFound => e
50
58
  assert_match /scope=badscope/, e.message
@@ -1,5 +1,4 @@
1
1
  # encoding: utf-8
2
-
3
2
  require File.dirname(__FILE__) + '/test_helper'
4
3
 
5
4
  class SlugTest < Test::Unit::TestCase
@@ -12,8 +11,8 @@ class SlugTest < Test::Unit::TestCase
12
11
  end
13
12
 
14
13
  should "indicate if it is the most recent slug" do
15
- post = Post.create!(:title => "test title", :content => "test content")
16
- post.title = "a new title"
14
+ post = Post.create!(:name => "test title")
15
+ post.name = "a new title"
17
16
  post.save!
18
17
  assert post.slugs.last.is_most_recent?
19
18
  assert !post.slugs.first.is_most_recent?
@@ -1,5 +1,4 @@
1
1
  # encoding: utf-8
2
-
3
2
  require File.dirname(__FILE__) + '/test_helper'
4
3
 
5
4
  class SluggedModelTest < Test::Unit::TestCase
@@ -7,17 +6,16 @@ class SluggedModelTest < Test::Unit::TestCase
7
6
  context "A slugged model with default FriendlyId options" do
8
7
 
9
8
  setup do
10
- Post.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :title, :use_slug => true)
11
- @post = Post.new :title => "Test post", :content => "Test content", :published => true
9
+ Post.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :name, :use_slug => true)
10
+ @post = Post.new :name => "Test post", :published => true
12
11
  @post.save!
13
12
  end
14
13
 
15
14
  teardown do
16
15
  Post.delete_all
17
16
  Person.delete_all
17
+ Place.delete_all
18
18
  Slug.delete_all
19
- Thing.delete_all
20
- LegacyThing.delete_all
21
19
  end
22
20
 
23
21
  should "have friendly_id options" do
@@ -51,7 +49,7 @@ class SluggedModelTest < Test::Unit::TestCase
51
49
  end
52
50
 
53
51
  should "generate slug text" do
54
- post = Post.new :title => "Test post", :content => "Test content"
52
+ post = Post.new :name => "Test post"
55
53
  assert_not_nil post.slug_text
56
54
  end
57
55
 
@@ -63,36 +61,36 @@ class SluggedModelTest < Test::Unit::TestCase
63
61
 
64
62
  should "raise an error if the friendly_id text is reserved" do
65
63
  assert_raises(FriendlyId::SlugGenerationError) do
66
- Post.create!(:title => "new")
64
+ Post.create!(:name => "new")
67
65
  end
68
66
  end
69
67
 
70
68
  should "raise an error if the friendly_id text is an empty string" do
71
69
  assert_raises(FriendlyId::SlugGenerationError) do
72
- Post.create(:title => "")
70
+ Post.create(:name => "")
73
71
  end
74
72
  end
75
73
 
76
74
  should "raise an error if the friendly_id text is nil" do
77
75
  assert_raises(FriendlyId::SlugGenerationError) do
78
- Post.create(:title => nil)
76
+ Post.create(:name => nil)
79
77
  end
80
78
  end
81
79
 
82
80
  should "raise an error if the normalized friendly id becomes blank" do
83
81
  assert_raises(FriendlyId::SlugGenerationError) do
84
- post = Post.create!(:title => "-.-")
82
+ post = Post.create!(:name => "-.-")
85
83
  end
86
84
  end
87
85
 
88
86
  should "not make a new slug unless the friendly_id method value has changed" do
89
- @post.content = "Changed content"
87
+ @post.published = !@post.published
90
88
  @post.save!
91
89
  assert_equal 1, @post.slugs.size
92
90
  end
93
91
 
94
92
  should "make a new slug if the friendly_id method value has changed" do
95
- @post.title = "Changed title"
93
+ @post.name = "Changed title"
96
94
  @post.save!
97
95
  assert_equal 2, @post.slugs.size
98
96
  end
@@ -102,12 +100,12 @@ class SluggedModelTest < Test::Unit::TestCase
102
100
  end
103
101
 
104
102
  should "increment sequence for duplicate slug names" do
105
- @post2 = Post.create! :title => @post.title, :content => "Test content for post2"
103
+ @post2 = Post.create! :name => @post.name
106
104
  assert_equal 2, @post2.slug.sequence
107
105
  end
108
106
 
109
107
  should "have a friendly_id that terminates with -- and the slug sequence if the sequence is greater than 1" do
110
- @post2 = Post.create! :title => @post.title, :content => "Test content for post2"
108
+ @post2 = Post.create! :name => @post.name
111
109
  assert_match(/--2\z/, @post2.friendly_id)
112
110
  end
113
111
 
@@ -116,36 +114,36 @@ class SluggedModelTest < Test::Unit::TestCase
116
114
  end
117
115
 
118
116
  should "not strip diacritics" do
119
- post = Post.new(:title => "¡Feliz año!")
117
+ post = Post.new(:name => "¡Feliz año!")
120
118
  assert_match(/#{'ñ'}/, post.slug_text)
121
119
  end
122
120
 
123
121
  should "not convert to ASCII" do
124
- post = Post.new(:title => "katakana: ゲコゴサザシジ")
122
+ post = Post.new(:name => "katakana: ゲコゴサザシジ")
125
123
  assert_equal "katakana-ゲコゴサザシジ", post.slug_text
126
124
  end
127
125
 
128
126
  should "allow the same friendly_id across models" do
129
- person = Person.create!(:name => @post.title)
130
- assert_equal person.friendly_id, @post.friendly_id
127
+ district = District.create!(:name => @post.name)
128
+ assert_equal district.friendly_id, @post.friendly_id
131
129
  end
132
130
 
133
131
  should "truncate slug text longer than the max length" do
134
- post = Post.new(:title => "a" * (Post.friendly_id_options[:max_length] + 1))
132
+ post = Post.new(:name => "a" * (Post.friendly_id_options[:max_length] + 1))
135
133
  assert_equal post.slug_text.length, Post.friendly_id_options[:max_length]
136
134
  end
137
135
 
138
136
  should "truncate slug in 'right way' when slug is unicode" do
139
- post = Post.new(:title => "ё" * 100 + 'ю' *(Post.friendly_id_options[:max_length] - 100 + 1))
137
+ post = Post.new(:name => "ё" * 100 + 'ю' *(Post.friendly_id_options[:max_length] - 100 + 1))
140
138
  assert_equal post.slug_text.mb_chars[-1], 'ю'
141
139
  end
142
140
 
143
141
  should "be able to reuse an old friendly_id without incrementing the sequence" do
144
- old_title = @post.title
142
+ old_title = @post.name
145
143
  old_friendly_id = @post.friendly_id
146
- @post.title = "A changed title"
144
+ @post.name = "A changed title"
147
145
  @post.save!
148
- @post.title = old_title
146
+ @post.name = old_title
149
147
  @post.save!
150
148
  assert_equal old_friendly_id, @post.friendly_id
151
149
  end
@@ -158,8 +156,8 @@ class SluggedModelTest < Test::Unit::TestCase
158
156
 
159
157
  # This emulates a fairly common issue where id's generated by fixtures are very high.
160
158
  should "continue to admit very large ids" do
161
- Thing.connection.execute("INSERT INTO things (id, name) VALUES (2147483647, 'big')")
162
- assert Thing.find(2147483647)
159
+ Person.connection.execute("INSERT INTO people (id, name) VALUES (2147483647, 'Joe Schmoe')")
160
+ assert Person.find(2147483647)
163
161
  end
164
162
 
165
163
  context "and configured to strip diacritics" do
@@ -168,19 +166,19 @@ class SluggedModelTest < Test::Unit::TestCase
168
166
  end
169
167
 
170
168
  should "strip diacritics from Roman alphabet based characters" do
171
- post = Post.new(:title => "¡Feliz año!")
169
+ post = Post.new(:name => "¡Feliz año!")
172
170
  assert_no_match(/#{'ñ'}/, post.slug_text)
173
171
  end
174
172
 
175
173
  should "raise an error if the friendly_id text is an empty string" do
176
174
  assert_raises(FriendlyId::SlugGenerationError) do
177
- Post.create(:title => "")
175
+ Post.create(:name => "")
178
176
  end
179
177
  end
180
178
 
181
179
  should "raise an error if the friendly_id text is nil" do
182
180
  assert_raises(FriendlyId::SlugGenerationError) do
183
- Post.create(:title => nil)
181
+ Post.create(:name => nil)
184
182
  end
185
183
  end
186
184
 
@@ -192,14 +190,14 @@ class SluggedModelTest < Test::Unit::TestCase
192
190
  end
193
191
 
194
192
  should "strip non-ascii characters" do
195
- post = Post.new(:title => "katakana: ゲコゴサザシジ")
193
+ post = Post.new(:name => "katakana: ゲコゴサザシジ")
196
194
  assert_equal "katakana", post.slug_text
197
195
  end
198
196
  end
199
197
 
200
198
  context "that uses a custom table name" do
201
199
  should "support normal CRUD operations" do
202
- assert thing = LegacyThing.create!(:name => "a name")
200
+ assert thing = Place.create!(:name => "a name")
203
201
  thing.name = "a new name"
204
202
  assert thing.save!
205
203
  assert thing.destroy
@@ -268,7 +266,7 @@ class SluggedModelTest < Test::Unit::TestCase
268
266
  context "when found using an outdated friendly id" do
269
267
  setup do
270
268
  old_id = @post.friendly_id
271
- @post.title = "Title changed"
269
+ @post.name = "Title changed"
272
270
  @post.save!
273
271
  @post = Post.find(old_id)
274
272
  end
@@ -291,10 +289,18 @@ class SluggedModelTest < Test::Unit::TestCase
291
289
 
292
290
  end
293
291
 
292
+ context "when table does not exist" do
293
+ should "not raise an error when doing friendly_id setup" do
294
+ assert_nothing_raised do
295
+ Question.has_friendly_id :title, :use_slug => true
296
+ end
297
+ end
298
+ end
299
+
294
300
  context "when using an array as the find argument" do
295
301
 
296
302
  setup do
297
- @post2 = Post.create!(:title => "another post", :content => "more content", :published => true)
303
+ @post2 = Post.create!(:name => "another post", :published => true)
298
304
  end
299
305
 
300
306
  should "return results when passed an array of non-friendly ids" do
@@ -314,7 +320,7 @@ class SluggedModelTest < Test::Unit::TestCase
314
320
  end
315
321
 
316
322
  should "return results when passed an array of non-friendly ids, of which one represents a record with multiple slugs" do
317
- @post2.update_attributes(:title => 'another post [updated]')
323
+ @post2.update_attributes(:name => 'another post [updated]')
318
324
  assert_equal 2, Post.find([@post.id, @post2.id]).size
319
325
  end
320
326
 
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require File.dirname(__FILE__) + '/test_helper'
4
2
 
5
3
  class STIModelTest < Test::Unit::TestCase
@@ -7,8 +5,8 @@ class STIModelTest < Test::Unit::TestCase
7
5
  context "A slugged model using single table inheritance" do
8
6
 
9
7
  setup do
10
- Novel.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :title, :use_slug => true)
11
- @novel = Novel.new :title => "Test novel"
8
+ Novel.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :name, :use_slug => true)
9
+ @novel = Novel.new :name => "Test novel"
12
10
  @novel.save!
13
11
  end
14
12
 
@@ -0,0 +1,6 @@
1
+ adapter: postgresql
2
+ host: localhost
3
+ port: 5432
4
+ username: postgres
5
+ database: friendly_id_test
6
+ encoding: utf8
@@ -0,0 +1,2 @@
1
+ adapter: sqlite3
2
+ database: ":memory:"
@@ -0,0 +1,45 @@
1
+ class CreateSupportModels < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :books do |t|
4
+ t.string :name
5
+ t.string :type
6
+ end
7
+ create_table :cities do |t|
8
+ t.string :name
9
+ t.string :my_slug
10
+ t.integer :population
11
+ end
12
+ create_table :countries do |t|
13
+ t.string :name
14
+ end
15
+ create_table :districts do |t|
16
+ t.string :name
17
+ t.string :cached_slug
18
+ end
19
+ create_table :events do |t|
20
+ t.string :name
21
+ t.datetime :event_date
22
+ end
23
+ create_table :legacy_table do |t|
24
+ t.string :name
25
+ end
26
+ create_table :people do |t|
27
+ t.string :name
28
+ end
29
+ create_table :posts do |t|
30
+ t.string :name
31
+ t.boolean :published
32
+ end
33
+ create_table :residents do |t|
34
+ t.string :name
35
+ t.integer :country_id
36
+ end
37
+ create_table :users do |t|
38
+ t.string :name
39
+ end
40
+ end
41
+
42
+ def self.down
43
+ end
44
+ end
45
+
@@ -1,6 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/test_helper'
2
2
  require "friendly_id/tasks"
3
- require "mocha"
4
3
 
5
4
  class TasksTest < Test::Unit::TestCase
6
5
 
@@ -42,7 +41,7 @@ class TasksTest < Test::Unit::TestCase
42
41
  context "The 'delete_slugs_for' task" do
43
42
 
44
43
  setup do
45
- @post = Post.create! :title => "Slugs Considered Harmful"
44
+ @post = Post.create! :name => "Slugs Considered Harmful"
46
45
  @city = City.create! :name => "Buenos Aires"
47
46
  end
48
47
 
@@ -59,9 +58,9 @@ class TasksTest < Test::Unit::TestCase
59
58
  end
60
59
 
61
60
  should "set the cached_slug column to NULL" do
62
- FriendlyId::Tasks.delete_slugs_for("City")
63
- @city.reload
64
- assert_nil @city.my_slug
61
+ District.create! :name => "Garment"
62
+ FriendlyId::Tasks.delete_slugs_for("District")
63
+ assert_nil District.first.cached_slug
65
64
  end
66
65
 
67
66
  end
@@ -69,7 +68,7 @@ class TasksTest < Test::Unit::TestCase
69
68
  context "The 'delete_old_slugs' task" do
70
69
 
71
70
  setup do
72
- @post = Post.create! :title => "Slugs Considered Harmful"
71
+ @post = Post.create! :name => "Slugs Considered Harmful"
73
72
  @city = City.create! :name => "Buenos Aires"
74
73
  City.connection.execute "UPDATE slugs SET created_at = '%s' WHERE id = %d" % [
75
74
  45.days.ago.strftime("%Y-%m-%d"), @city.slug.id]
@@ -1,38 +1,104 @@
1
- # encoding: utf-8
2
-
3
1
  $:.unshift(File.dirname(__FILE__) + '/../lib')
4
2
  $:.unshift(File.dirname(__FILE__))
3
+
5
4
  $KCODE = 'UTF8' if RUBY_VERSION < '1.9'
6
5
  $VERBOSE = false
6
+
7
+ require 'rubygems'
7
8
  require 'test/unit'
8
9
  require 'contest'
9
- # You can use "rake test AR_VERSION=2.0.5" to test against 2.0.5, for example.
10
+ require 'mocha'
11
+
12
+ # You can use "rake test AR_VERSION=2.2.3" to test against 2.2.3 for example.
10
13
  # The default is to use the latest installed ActiveRecord.
11
14
  if ENV["AR_VERSION"]
12
15
  gem 'activerecord', "#{ENV["AR_VERSION"]}"
13
16
  gem 'activesupport', "#{ENV["AR_VERSION"]}"
14
17
  end
18
+
15
19
  require 'active_record'
16
20
  require 'active_support'
21
+ require 'friendly_id'
22
+ require File.dirname(__FILE__) + '/../generators/friendly_id/templates/create_slugs'
23
+ require File.dirname(__FILE__) + '/support/models'
17
24
 
18
- ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
19
- silence_stream(STDOUT) do
20
- load(File.dirname(__FILE__) + "/schema.rb")
21
- end
25
+ local_db_settings = File.dirname(__FILE__) + '/support/database.yml'
26
+ default_db_settings = File.dirname(__FILE__) + '/support/database.yml.sqlite3'
27
+ db_settings = File.exists?(local_db_settings) ? local_db_settings : default_db_settings
28
+ ActiveRecord::Base.establish_connection(YAML::load(File.open(db_settings)))
22
29
 
23
30
  class ActiveRecord::Base
24
31
  def log_protected_attribute_removal(*args) end
25
32
  end
26
33
 
27
- require 'friendly_id'
28
- require 'models/post'
29
- require 'models/person'
30
- require 'models/user'
31
- require 'models/country'
32
- require 'models/book'
33
- require 'models/novel'
34
- require 'models/thing'
35
- require 'models/event'
36
- require 'models/city'
37
- require 'models/district'
38
- require 'models/legacy_thing'
34
+ ActiveRecord::Base.connection.tables.each do |table|
35
+ ActiveRecord::Base.connection.drop_table(table)
36
+ end
37
+ ActiveRecord::Migration.verbose = false
38
+ CreateSlugs.up
39
+ CreateSupportModels.up
40
+
41
+ # A model that uses the automagically configured "cached_slug" column
42
+ class District < ActiveRecord::Base
43
+ has_friendly_id :name, :use_slug => true
44
+ end
45
+
46
+ # A model that specifies a custom cached slug column
47
+ class City < ActiveRecord::Base
48
+ attr_accessible :name
49
+ has_friendly_id :name, :use_slug => true, :cache_column => 'my_slug'
50
+ end
51
+
52
+ # A model with a custom slug text normalizer
53
+ class Person < ActiveRecord::Base
54
+ has_friendly_id :name, :use_slug => true do |text|
55
+ text.upcase
56
+ end
57
+ end
58
+
59
+ # A slugged model that uses a scope
60
+ class Resident < ActiveRecord::Base
61
+ belongs_to :country
62
+ has_friendly_id :name, :use_slug => true, :scope => :country
63
+ end
64
+
65
+ # A model used as a scope
66
+ class Country < ActiveRecord::Base
67
+ has_many :people
68
+ has_friendly_id :name, :use_slug => true
69
+ end
70
+
71
+ # A model that doesn't use slugs
72
+ class User < ActiveRecord::Base
73
+ has_friendly_id :name
74
+ end
75
+
76
+ # A model that uses default slug settings and has a named scope
77
+ class Post < ActiveRecord::Base
78
+ has_friendly_id :name, :use_slug => true
79
+ named_scope :published, :conditions => { :published => true }
80
+ end
81
+
82
+ # Model that uses a custom table name
83
+ class Place < ActiveRecord::Base
84
+ self.table_name = "legacy_table"
85
+ has_friendly_id :name, :use_slug => true
86
+ end
87
+
88
+ # A model that uses a datetime field for its friendly_id
89
+ class Event < ActiveRecord::Base
90
+ has_friendly_id :event_date, :use_slug => true
91
+ end
92
+
93
+ # A base model for single table inheritence
94
+ class Book < ActiveRecord::Base ; end
95
+
96
+ # A model that uses STI
97
+ class Novel < ::Book
98
+ has_friendly_id :name, :use_slug => true
99
+ end
100
+
101
+ # A model with no table
102
+ class Question < ActiveRecord::Base
103
+ has_friendly_id :name, :use_slug => true
104
+ end