friendly_id4 4.0.0.beta4 → 4.0.0.beta5
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +4 -0
- data/README.md +21 -24
- data/Rakefile +1 -1
- data/friendly_id.gemspec +2 -2
- data/lib/friendly_id.rb +102 -8
- data/lib/friendly_id/base.rb +76 -8
- data/lib/friendly_id/configuration.rb +9 -27
- data/lib/friendly_id/finder_methods.rb +8 -0
- data/lib/friendly_id/history.rb +35 -0
- data/lib/friendly_id/migration.rb +1 -0
- data/lib/friendly_id/object_utils.rb +16 -6
- data/lib/friendly_id/reserved.rb +46 -0
- data/lib/friendly_id/scoped.rb +101 -19
- data/lib/friendly_id/slug.rb +3 -0
- data/lib/friendly_id/slug_sequencer.rb +3 -0
- data/lib/friendly_id/slugged.rb +180 -8
- data/lib/generators/friendly_id_generator.rb +3 -0
- data/test/base_test.rb +23 -0
- data/test/configuration_test.rb +6 -6
- data/test/core_test.rb +3 -11
- data/test/helper.rb +2 -2
- data/test/history_test.rb +9 -9
- data/test/object_utils_test.rb +3 -3
- data/test/reserved_test.rb +26 -0
- data/test/scoped_test.rb +8 -8
- data/test/shared.rb +15 -15
- data/test/slugged_test.rb +30 -20
- metadata +19 -18
- data/Guide.md +0 -363
- data/lib/friendly_id/version.rb +0 -9
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'rails/generators'
|
2
2
|
require 'rails/generators/migration'
|
3
3
|
|
4
|
+
# This generator adds a migration for the {FriendlyId::History
|
5
|
+
# FriendlyId::History} addon.
|
4
6
|
class FriendlyIdGenerator < Rails::Generators::Base
|
5
7
|
include Rails::Generators::Migration
|
6
8
|
|
7
9
|
source_root File.expand_path('../../friendly_id', __FILE__)
|
8
10
|
|
11
|
+
# Copies the migration template to db/migrate.
|
9
12
|
def copy_files(*args)
|
10
13
|
migration_template 'migration.rb', 'db/migrate/create_friendly_id_slugs.rb'
|
11
14
|
end
|
data/test/base_test.rb
CHANGED
@@ -28,4 +28,27 @@ class CoreTest < MiniTest::Unit::TestCase
|
|
28
28
|
assert_equal :bar, klass.friendly_id_config.slug_column
|
29
29
|
end
|
30
30
|
|
31
|
+
test "the block passed to friendly_id should be evaluated before arguments" do
|
32
|
+
klass = Class.new(ActiveRecord::Base) do
|
33
|
+
extend FriendlyId
|
34
|
+
friendly_id :foo do |config|
|
35
|
+
config.base = :bar
|
36
|
+
end
|
37
|
+
end
|
38
|
+
assert_equal :foo, klass.friendly_id_config.base
|
39
|
+
end
|
40
|
+
|
41
|
+
test "should allow defaults to be set via a block" do
|
42
|
+
begin
|
43
|
+
FriendlyId.defaults do |config|
|
44
|
+
config.base = :foo
|
45
|
+
end
|
46
|
+
klass = Class.new(ActiveRecord::Base) do
|
47
|
+
extend FriendlyId
|
48
|
+
end
|
49
|
+
assert_equal :foo, klass.friendly_id_config.base
|
50
|
+
ensure
|
51
|
+
FriendlyId.instance_variable_set :@defaults, nil
|
52
|
+
end
|
53
|
+
end
|
31
54
|
end
|
data/test/configuration_test.rb
CHANGED
@@ -5,22 +5,22 @@ class ConfigurationTest < MiniTest::Unit::TestCase
|
|
5
5
|
include FriendlyId::Test
|
6
6
|
|
7
7
|
def setup
|
8
|
-
@
|
8
|
+
@model_class = Class.new(ActiveRecord::Base)
|
9
9
|
end
|
10
10
|
|
11
|
-
test "should set
|
12
|
-
config = FriendlyId::Configuration.new @
|
13
|
-
assert_equal @
|
11
|
+
test "should set model class on initialization" do
|
12
|
+
config = FriendlyId::Configuration.new @model_class
|
13
|
+
assert_equal @model_class, config.model_class
|
14
14
|
end
|
15
15
|
|
16
16
|
test "should set options on initialization if present" do
|
17
|
-
config = FriendlyId::Configuration.new @
|
17
|
+
config = FriendlyId::Configuration.new @model_class, :base => "hello"
|
18
18
|
assert_equal "hello", config.base
|
19
19
|
end
|
20
20
|
|
21
21
|
test "should raise error if passed unrecognized option" do
|
22
22
|
assert_raises NoMethodError do
|
23
|
-
FriendlyId::Configuration.new @
|
23
|
+
FriendlyId::Configuration.new @model_class, :foo => "bar"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
data/test/core_test.rb
CHANGED
@@ -12,7 +12,7 @@ class CoreTest < MiniTest::Unit::TestCase
|
|
12
12
|
include FriendlyId::Test
|
13
13
|
include FriendlyId::Test::Shared
|
14
14
|
|
15
|
-
def
|
15
|
+
def model_class
|
16
16
|
Author
|
17
17
|
end
|
18
18
|
|
@@ -21,18 +21,10 @@ class CoreTest < MiniTest::Unit::TestCase
|
|
21
21
|
end
|
22
22
|
|
23
23
|
test "model classes should have a friendly id config" do
|
24
|
-
assert
|
25
|
-
end
|
26
|
-
|
27
|
-
test "should reserve 'new' and 'edit' by default" do
|
28
|
-
["new", "edit"].each do |word|
|
29
|
-
transaction do
|
30
|
-
assert_raises(ActiveRecord::RecordInvalid) {klass.create! :name => word}
|
31
|
-
end
|
32
|
-
end
|
24
|
+
assert model_class.friendly_id(:name).friendly_id_config
|
33
25
|
end
|
34
26
|
|
35
27
|
test "instances should have a friendly id" do
|
36
|
-
with_instance_of(
|
28
|
+
with_instance_of(model_class) {|record| assert record.friendly_id}
|
37
29
|
end
|
38
30
|
end
|
data/test/helper.rb
CHANGED
@@ -37,9 +37,9 @@ module FriendlyId
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def with_instance_of(*args)
|
40
|
-
|
40
|
+
model_class = args.shift
|
41
41
|
args[0] ||= {:name => "a"}
|
42
|
-
transaction { yield
|
42
|
+
transaction { yield model_class.create!(*args) }
|
43
43
|
end
|
44
44
|
|
45
45
|
module Database
|
data/test/history_test.rb
CHANGED
@@ -10,16 +10,16 @@ class HistoryTest < MiniTest::Unit::TestCase
|
|
10
10
|
include FriendlyId::Test
|
11
11
|
include FriendlyId::Test::Shared
|
12
12
|
|
13
|
-
def
|
13
|
+
def model_class
|
14
14
|
Manual
|
15
15
|
end
|
16
16
|
|
17
17
|
test "should insert record in slugs table on create" do
|
18
|
-
with_instance_of(
|
18
|
+
with_instance_of(model_class) {|record| assert !record.friendly_id_slugs.empty?}
|
19
19
|
end
|
20
20
|
|
21
21
|
test "should not create new slug record if friendly_id is not changed" do
|
22
|
-
with_instance_of(
|
22
|
+
with_instance_of(model_class) do |record|
|
23
23
|
record.active = true
|
24
24
|
record.save!
|
25
25
|
assert_equal 1, FriendlyIdSlug.count
|
@@ -27,7 +27,7 @@ class HistoryTest < MiniTest::Unit::TestCase
|
|
27
27
|
end
|
28
28
|
|
29
29
|
test "should create new slug record when friendly_id changes" do
|
30
|
-
with_instance_of(
|
30
|
+
with_instance_of(model_class) do |record|
|
31
31
|
record.name = record.name + "b"
|
32
32
|
record.save!
|
33
33
|
assert_equal 2, FriendlyIdSlug.count
|
@@ -35,20 +35,20 @@ class HistoryTest < MiniTest::Unit::TestCase
|
|
35
35
|
end
|
36
36
|
|
37
37
|
test "should be findable by old slugs" do
|
38
|
-
with_instance_of(
|
38
|
+
with_instance_of(model_class) do |record|
|
39
39
|
old_friendly_id = record.friendly_id
|
40
40
|
record.name = record.name + "b"
|
41
41
|
record.save!
|
42
|
-
assert found =
|
42
|
+
assert found = model_class.find_by_friendly_id(old_friendly_id)
|
43
43
|
assert !found.readonly?
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
test "should raise error if used with scoped" do
|
48
|
-
|
49
|
-
|
48
|
+
model_class = Class.new(ActiveRecord::Base)
|
49
|
+
model_class.extend FriendlyId
|
50
50
|
assert_raises RuntimeError do
|
51
|
-
|
51
|
+
model_class.friendly_id :name, :use => [:history, :scoped]
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
data/test/object_utils_test.rb
CHANGED
@@ -19,8 +19,8 @@ class ObjectUtilsTest < MiniTest::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
|
21
21
|
test "ActiveRecord::Base instances should be unfriendly_ids" do
|
22
|
-
|
23
|
-
|
24
|
-
assert
|
22
|
+
model_class = Class.new(ActiveRecord::Base)
|
23
|
+
model_class.table_name = "authors"
|
24
|
+
assert model_class.new.unfriendly_id?
|
25
25
|
end
|
26
26
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path("../helper.rb", __FILE__)
|
2
|
+
|
3
|
+
class ReservedTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
include FriendlyId::Test
|
6
|
+
|
7
|
+
class Journalist < ActiveRecord::Base
|
8
|
+
extend FriendlyId
|
9
|
+
friendly_id :name
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def model_class
|
14
|
+
Journalist
|
15
|
+
end
|
16
|
+
|
17
|
+
test "should reserve 'new' and 'edit' by default" do
|
18
|
+
["new", "edit"].each do |word|
|
19
|
+
transaction do
|
20
|
+
assert_raises(ActiveRecord::RecordInvalid) {model_class.create! :name => word}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
data/test/scoped_test.rb
CHANGED
@@ -16,7 +16,7 @@ class ScopedTest < MiniTest::Unit::TestCase
|
|
16
16
|
include FriendlyId::Test
|
17
17
|
include FriendlyId::Test::Shared
|
18
18
|
|
19
|
-
def
|
19
|
+
def model_class
|
20
20
|
Novel
|
21
21
|
end
|
22
22
|
|
@@ -25,10 +25,10 @@ class ScopedTest < MiniTest::Unit::TestCase
|
|
25
25
|
end
|
26
26
|
|
27
27
|
test "should detect scope column from explicit column name" do
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
assert_equal "dummy",
|
28
|
+
model_class = Class.new(ActiveRecord::Base)
|
29
|
+
model_class.extend FriendlyId
|
30
|
+
model_class.friendly_id :empty, :use => :scoped, :scope => :dummy
|
31
|
+
assert_equal "dummy", model_class.friendly_id_config.scope_column
|
32
32
|
end
|
33
33
|
|
34
34
|
test "should allow duplicate slugs outside scope" do
|
@@ -48,10 +48,10 @@ class ScopedTest < MiniTest::Unit::TestCase
|
|
48
48
|
end
|
49
49
|
|
50
50
|
test "should raise error if used with history" do
|
51
|
-
|
52
|
-
|
51
|
+
model_class = Class.new(ActiveRecord::Base)
|
52
|
+
model_class.extend FriendlyId
|
53
53
|
assert_raises RuntimeError do
|
54
|
-
|
54
|
+
model_class.friendly_id :name, :use => [:scoped, :history]
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
data/test/shared.rb
CHANGED
@@ -3,69 +3,69 @@ module FriendlyId
|
|
3
3
|
module Shared
|
4
4
|
|
5
5
|
test "finds should respect conditions" do
|
6
|
-
with_instance_of(
|
6
|
+
with_instance_of(model_class) do |record|
|
7
7
|
assert_raises(ActiveRecord::RecordNotFound) do
|
8
|
-
|
8
|
+
model_class.where("1 = 2").find record.friendly_id
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
test "should be findable by friendly id" do
|
14
|
-
with_instance_of(
|
14
|
+
with_instance_of(model_class) {|record| assert model_class.find record.friendly_id}
|
15
15
|
end
|
16
16
|
|
17
17
|
test "should be findable by id as integer" do
|
18
|
-
with_instance_of(
|
18
|
+
with_instance_of(model_class) {|record| assert model_class.find record.id.to_i}
|
19
19
|
end
|
20
20
|
|
21
21
|
test "should be findable by id as string" do
|
22
|
-
with_instance_of(
|
22
|
+
with_instance_of(model_class) {|record| assert model_class.find record.id.to_s}
|
23
23
|
end
|
24
24
|
|
25
25
|
test "should be findable by numeric friendly_id" do
|
26
|
-
with_instance_of(
|
26
|
+
with_instance_of(model_class, :name => "206") {|record| assert model_class.find record.friendly_id}
|
27
27
|
end
|
28
28
|
|
29
29
|
test "to_param should return the friendly_id" do
|
30
|
-
with_instance_of(
|
30
|
+
with_instance_of(model_class) {|record| assert_equal record.friendly_id, record.to_param}
|
31
31
|
end
|
32
32
|
|
33
33
|
test "should be findable by themselves" do
|
34
|
-
with_instance_of(
|
34
|
+
with_instance_of(model_class) {|record| assert_equal record, model_class.find(record)}
|
35
35
|
end
|
36
36
|
|
37
37
|
test "updating record's other values should not change the friendly_id" do
|
38
|
-
with_instance_of
|
38
|
+
with_instance_of model_class do |record|
|
39
39
|
old = record.friendly_id
|
40
40
|
record.update_attributes! :active => false
|
41
|
-
assert
|
41
|
+
assert model_class.find old
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
test "instances found by a single id should not be read-only" do
|
46
|
-
with_instance_of(
|
46
|
+
with_instance_of(model_class) {|record| assert !model_class.find(record.friendly_id).readonly?}
|
47
47
|
end
|
48
48
|
|
49
49
|
test "failing finds with unfriendly_id should raise errors normally" do
|
50
|
-
assert_raises(ActiveRecord::RecordNotFound) {
|
50
|
+
assert_raises(ActiveRecord::RecordNotFound) {model_class.find 0}
|
51
51
|
end
|
52
52
|
|
53
53
|
test "should return numeric id if the friendly_id is nil" do
|
54
|
-
with_instance_of(
|
54
|
+
with_instance_of(model_class) do |record|
|
55
55
|
record.expects(:friendly_id).returns(nil)
|
56
56
|
assert_equal record.id.to_s, record.to_param
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
60
|
test "should return numeric id if the friendly_id is an empty string" do
|
61
|
-
with_instance_of(
|
61
|
+
with_instance_of(model_class) do |record|
|
62
62
|
record.expects(:friendly_id).returns("")
|
63
63
|
assert_equal record.id.to_s, record.to_param
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
test "should return numeric id if the friendly_id is blank" do
|
68
|
-
with_instance_of(
|
68
|
+
with_instance_of(model_class) do |record|
|
69
69
|
record.expects(:friendly_id).returns(" ")
|
70
70
|
assert_equal record.id.to_s, record.to_param
|
71
71
|
end
|
data/test/slugged_test.rb
CHANGED
@@ -12,16 +12,16 @@ class SluggedTest < MiniTest::Unit::TestCase
|
|
12
12
|
include FriendlyId::Test
|
13
13
|
include FriendlyId::Test::Shared
|
14
14
|
|
15
|
-
def
|
15
|
+
def model_class
|
16
16
|
Journalist
|
17
17
|
end
|
18
18
|
|
19
19
|
test "configuration should have a sequence_separator" do
|
20
|
-
assert !
|
20
|
+
assert !model_class.friendly_id_config.sequence_separator.empty?
|
21
21
|
end
|
22
22
|
|
23
23
|
test "should make a new slug if the friendly_id method value has changed" do
|
24
|
-
with_instance_of
|
24
|
+
with_instance_of model_class do |record|
|
25
25
|
record.name = "Changed Value"
|
26
26
|
record.save!
|
27
27
|
assert_equal "changed-value", record.slug
|
@@ -29,21 +29,31 @@ class SluggedTest < MiniTest::Unit::TestCase
|
|
29
29
|
end
|
30
30
|
|
31
31
|
test "should increment the slug sequence for duplicate friendly ids" do
|
32
|
-
with_instance_of
|
33
|
-
record2 =
|
32
|
+
with_instance_of model_class do |record|
|
33
|
+
record2 = model_class.create! :name => record.name
|
34
34
|
assert record2.friendly_id.match(/2\z/)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
test "should not add slug sequence on update after other conflicting slugs were added" do
|
39
|
-
with_instance_of
|
39
|
+
with_instance_of model_class do |record|
|
40
40
|
old = record.friendly_id
|
41
|
-
record2 =
|
41
|
+
record2 = model_class.create! :name => record.name
|
42
42
|
record.save!
|
43
43
|
record.reload
|
44
44
|
assert_equal old, record.to_param
|
45
45
|
end
|
46
46
|
end
|
47
|
+
|
48
|
+
test "should not increment sequence on save" do
|
49
|
+
with_instance_of model_class do |record|
|
50
|
+
record2 = model_class.create! :name => record.name
|
51
|
+
record2.active = !record2.active
|
52
|
+
record2.save!
|
53
|
+
assert record2.friendly_id.match(/2\z/)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
47
57
|
end
|
48
58
|
|
49
59
|
class SlugSequencerTest < MiniTest::Unit::TestCase
|
@@ -51,12 +61,12 @@ class SlugSequencerTest < MiniTest::Unit::TestCase
|
|
51
61
|
include FriendlyId::Test
|
52
62
|
|
53
63
|
test "should quote column names" do
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
64
|
+
model_class = Class.new(ActiveRecord::Base)
|
65
|
+
model_class.table_name = "journalists"
|
66
|
+
model_class.extend FriendlyId
|
67
|
+
model_class.friendly_id :name, :use => :slugged, :slug_column => "strange name"
|
58
68
|
begin
|
59
|
-
with_instance_of(
|
69
|
+
with_instance_of(model_class) {|record| assert model_class.find(record.friendly_id)}
|
60
70
|
rescue ActiveRecord::StatementInvalid
|
61
71
|
flunk "column name was not quoted"
|
62
72
|
end
|
@@ -72,20 +82,20 @@ class SlugSeparatorTest < MiniTest::Unit::TestCase
|
|
72
82
|
friendly_id :name, :use => :slugged, :sequence_separator => ":"
|
73
83
|
end
|
74
84
|
|
75
|
-
def
|
85
|
+
def model_class
|
76
86
|
Journalist
|
77
87
|
end
|
78
88
|
|
79
89
|
test "should increment sequence with configured sequence separator" do
|
80
|
-
with_instance_of
|
81
|
-
record2 =
|
90
|
+
with_instance_of model_class do |record|
|
91
|
+
record2 = model_class.create! :name => record.name
|
82
92
|
assert record2.friendly_id.match(/:2\z/)
|
83
93
|
end
|
84
94
|
end
|
85
95
|
|
86
96
|
test "should detect when a sequenced slug has changed" do
|
87
|
-
with_instance_of
|
88
|
-
record2 =
|
97
|
+
with_instance_of model_class do |record|
|
98
|
+
record2 = model_class.create! :name => record.name
|
89
99
|
assert !record2.slug_sequencer.slug_changed?
|
90
100
|
record2.name = "hello world"
|
91
101
|
assert record2.slug_sequencer.slug_changed?
|
@@ -96,14 +106,14 @@ end
|
|
96
106
|
class SluggedRegressionsTest < MiniTest::Unit::TestCase
|
97
107
|
include FriendlyId::Test
|
98
108
|
|
99
|
-
def
|
109
|
+
def model_class
|
100
110
|
Journalist
|
101
111
|
end
|
102
112
|
|
103
113
|
test "should increment the slug sequence for duplicate friendly ids beyond 10" do
|
104
|
-
with_instance_of
|
114
|
+
with_instance_of model_class do |record|
|
105
115
|
(2..12).each do |i|
|
106
|
-
r =
|
116
|
+
r = model_class.create! :name => record.name
|
107
117
|
assert r.friendly_id.match(/#{i}\z/)
|
108
118
|
end
|
109
119
|
end
|