friendly_id 4.0.10.1 → 4.1.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changelog.md +2 -8
- data/Gemfile +1 -1
- data/Guide.rdoc +16 -44
- data/README.md +4 -4
- data/friendly_id.gemspec +7 -6
- data/lib/friendly_id.rb +3 -8
- data/lib/friendly_id/configuration.rb +10 -0
- data/lib/friendly_id/history.rb +8 -6
- data/lib/friendly_id/migration.rb +3 -1
- data/lib/friendly_id/scoped.rb +15 -28
- data/lib/friendly_id/slug.rb +1 -0
- data/lib/friendly_id/slug_generator.rb +1 -2
- data/test/helper.rb +1 -1
- data/test/history_test.rb +64 -25
- data/test/schema.rb +13 -2
- data/test/scoped_test.rb +0 -11
- data/test/slugged_test.rb +0 -6
- metadata +74 -59
- checksums.yaml +0 -7
- data/lib/friendly_id/.gitattributes +0 -1
- data/lib/friendly_id/version.rb +0 -3
data/Changelog.md
CHANGED
@@ -6,15 +6,9 @@ suggestions, ideas and improvements to FriendlyId.
|
|
6
6
|
* Table of Contents
|
7
7
|
{:toc}
|
8
8
|
|
9
|
-
## 4.0.
|
9
|
+
## 4.1.0.beta.1 (2013-01-09)
|
10
10
|
|
11
|
-
|
12
|
-
* Fixed links in docs.
|
13
|
-
|
14
|
-
## 4.0.10 (2013-08-10)
|
15
|
-
|
16
|
-
* Fixed table prefixes/suffixes being ignored (Jesse Farless)
|
17
|
-
* Fixed sequence generation for slugs containing numbers (Adam Carroll)
|
11
|
+
Made the :scoped and :history modules compatible with each other (Andre Duffeck)
|
18
12
|
|
19
13
|
## 4.0.9 (2012-10-31)
|
20
14
|
|
data/Gemfile
CHANGED
data/Guide.rdoc
CHANGED
@@ -114,8 +114,9 @@ store them in a field in your model. By default, this field must be named
|
|
114
114
|
+:slug+, though you may change this using the
|
115
115
|
{FriendlyId::Slugged::Configuration#slug_column slug_column} configuration
|
116
116
|
option. You should add an index to this column, and in most cases, make it
|
117
|
-
unique.
|
118
|
-
|
117
|
+
unique. Do not make the column unique in case you wish to scope the slug
|
118
|
+
(more on this later). You may also wish to constrain it to NOT NULL, but this
|
119
|
+
depends on your app's behavior and requirements.
|
119
120
|
|
120
121
|
=== Example Setup
|
121
122
|
|
@@ -295,8 +296,6 @@ model.
|
|
295
296
|
|
296
297
|
=== Considerations
|
297
298
|
|
298
|
-
This module is incompatible with the +:scoped+ module.
|
299
|
-
|
300
299
|
Because recording slug history requires creating additional database records,
|
301
300
|
this module has an impact on the performance of the associated model's +create+
|
302
301
|
method.
|
@@ -356,27 +355,8 @@ Without :scoped in this case, one of the restaurants would have the slug
|
|
356
355
|
The value for the +:scope+ option can be the name of a +belongs_to+ relation, or
|
357
356
|
a column.
|
358
357
|
|
359
|
-
|
360
|
-
|
361
|
-
class Cuisine < ActiveRecord::Base
|
362
|
-
extend FriendlyId
|
363
|
-
has_many :restaurants
|
364
|
-
friendly_id :name, :use => :slugged
|
365
|
-
end
|
366
|
-
|
367
|
-
class City < ActiveRecord::Base
|
368
|
-
extend FriendlyId
|
369
|
-
has_many :restaurants
|
370
|
-
friendly_id :name, :use => :slugged
|
371
|
-
end
|
372
|
-
|
373
|
-
class Restaurant < ActiveRecord::Base
|
374
|
-
extend FriendlyId
|
375
|
-
belongs_to :city
|
376
|
-
friendly_id :name, :use => :scoped, :scope => [:city, :cuisine]
|
377
|
-
end
|
378
|
-
|
379
|
-
All supplied values will be used to determine scope.
|
358
|
+
Please do note that you must drop the uniqueness constraint on the slug's
|
359
|
+
column in the database when you're scoping the slug.
|
380
360
|
|
381
361
|
=== Finding Records by Friendly ID
|
382
362
|
|
@@ -485,7 +465,7 @@ If you don't pass in a locale argument, FriendlyId::SimpleI18n will just use the
|
|
485
465
|
current locale:
|
486
466
|
|
487
467
|
I18n.with_locale(:es) do
|
488
|
-
post.set_friendly_id("
|
468
|
+
post.set_friendly_id("la-guerra-de-las-galaxas")
|
489
469
|
end
|
490
470
|
|
491
471
|
|
@@ -517,15 +497,12 @@ Finds will take the current locale into consideration:
|
|
517
497
|
I18n.locale = :en
|
518
498
|
Post.find("star-wars")
|
519
499
|
|
520
|
-
Additionally, finds will fall back to the default locale:
|
521
|
-
|
522
|
-
I18n.locale = :it
|
523
|
-
Post.find("star-wars")
|
524
|
-
|
525
500
|
To find a slug by an explicit locale, perform the find inside a block
|
526
501
|
passed to I18n's +with_locale+ method:
|
527
502
|
|
528
|
-
I18n.with_locale(:it)
|
503
|
+
I18n.with_locale(:it) do
|
504
|
+
Post.find("guerre-stellari")
|
505
|
+
end
|
529
506
|
|
530
507
|
=== Creating Records
|
531
508
|
|
@@ -533,17 +510,12 @@ When new records are created, the slug is generated for the current locale only.
|
|
533
510
|
|
534
511
|
=== Translating Slugs
|
535
512
|
|
536
|
-
To translate an existing record's friendly_id,
|
537
|
-
|
538
|
-
you add is properly escaped, transliterated and sequenced:
|
539
|
-
|
540
|
-
post = Post.create :name => "Star Wars"
|
541
|
-
post.set_friendly_id("Guerre stellari", :it)
|
513
|
+
To translate an existing record's friendly_id, simply change the locale and
|
514
|
+
assign a value to the +slug+ field:
|
542
515
|
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
I18n.with_locale(:it) { post.set_friendly_id("Guerre stellari") }
|
516
|
+
I18n.with_locale(:it) do
|
517
|
+
post.slug = "guerre-stellari"
|
518
|
+
end
|
547
519
|
|
548
520
|
|
549
521
|
== Reserved Words
|
@@ -574,6 +546,6 @@ For example:
|
|
574
546
|
after_validation :move_friendly_id_error_to_name
|
575
547
|
|
576
548
|
def move_friendly_id_error_to_name
|
577
|
-
errors.
|
549
|
+
errors.messages[:name] = errors.messages.delete(:friendly_id)
|
578
550
|
end
|
579
|
-
end
|
551
|
+
end
|
data/README.md
CHANGED
@@ -27,16 +27,16 @@ FriendlyId is compatible with Active Record **3.0** and higher.
|
|
27
27
|
|
28
28
|
FriendlyId 4.x introduces many changes incompatible with 3.x. If you're
|
29
29
|
upgrading, please [read the
|
30
|
-
docs](http://rubydoc.info/github/norman/friendly_id/
|
30
|
+
docs](http://rubydoc.info/github/norman/friendly_id/master/file/WhatsNew.md) to see what's
|
31
31
|
new.
|
32
32
|
|
33
33
|
## Docs
|
34
34
|
|
35
35
|
The current docs can always be found
|
36
|
-
[here](http://rubydoc.info/github/norman/friendly_id/
|
36
|
+
[here](http://rubydoc.info/github/norman/friendly_id/master/frames).
|
37
37
|
|
38
38
|
The best place to start is with the
|
39
|
-
[Guide](http://rubydoc.info/github/norman/friendly_id/
|
39
|
+
[Guide](http://rubydoc.info/github/norman/friendly_id/master/file/Guide.rdoc),
|
40
40
|
which compiles the top-level RDocs into one outlined document.
|
41
41
|
|
42
42
|
You might also want to watch Ryan Bates's [Railscast on FriendlyId](http://railscasts.com/episodes/314-pretty-urls-with-friendlyid).
|
@@ -49,7 +49,7 @@ You might also want to watch Ryan Bates's [Railscast on FriendlyId](http://rails
|
|
49
49
|
|
50
50
|
cd my_app
|
51
51
|
|
52
|
-
gem "friendly_id", "~> 4.0.
|
52
|
+
gem "friendly_id", "~> 4.0.1"
|
53
53
|
|
54
54
|
rails generate scaffold user name:string slug:string
|
55
55
|
|
data/friendly_id.gemspec
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
require "friendly_id"
|
3
5
|
|
4
6
|
Gem::Specification.new do |s|
|
5
7
|
s.name = "friendly_id"
|
@@ -7,17 +9,16 @@ Gem::Specification.new do |s|
|
|
7
9
|
s.authors = ["Norman Clarke", "Philip Arndt"]
|
8
10
|
s.email = ["norman@njclarke.com", "parndt@gmail.com"]
|
9
11
|
s.homepage = "http://github.com/norman/friendly_id"
|
10
|
-
s.license = 'MIT'
|
11
12
|
s.summary = "A comprehensive slugging and pretty-URL plugin."
|
12
13
|
s.rubyforge_project = "friendly_id"
|
13
14
|
s.files = `git ls-files`.split("\n")
|
14
15
|
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
15
16
|
s.require_paths = ["lib"]
|
16
17
|
|
17
|
-
s.
|
18
|
-
s.add_development_dependency "
|
19
|
-
s.add_development_dependency "minitest", "
|
20
|
-
s.add_development_dependency "mocha"
|
18
|
+
s.add_development_dependency "railties", "~> 3.2.0"
|
19
|
+
s.add_development_dependency "activerecord", "~> 3.2.0"
|
20
|
+
s.add_development_dependency "minitest", "3.2.0"
|
21
|
+
s.add_development_dependency "mocha"
|
21
22
|
s.add_development_dependency "maruku"
|
22
23
|
s.add_development_dependency "yard"
|
23
24
|
s.add_development_dependency "i18n"
|
data/lib/friendly_id.rb
CHANGED
@@ -44,6 +44,9 @@ with numeric ids:
|
|
44
44
|
=end
|
45
45
|
module FriendlyId
|
46
46
|
|
47
|
+
# The current version.
|
48
|
+
VERSION = "4.1.0.beta.1"
|
49
|
+
|
47
50
|
@mutex = Mutex.new
|
48
51
|
|
49
52
|
autoload :History, "friendly_id/history"
|
@@ -108,12 +111,4 @@ module FriendlyId
|
|
108
111
|
@defaults ||= lambda {|config| config.use :reserved}
|
109
112
|
end
|
110
113
|
end
|
111
|
-
|
112
|
-
# Set the ActiveRecord table name prefix to friendly_id_
|
113
|
-
#
|
114
|
-
# This makes 'slugs' into 'friendly_id_slugs' and also respects any
|
115
|
-
# 'global' table_name_prefix set on ActiveRecord::Base.
|
116
|
-
def self.table_name_prefix
|
117
|
-
"#{ActiveRecord::Base.table_name_prefix}friendly_id_"
|
118
|
-
end
|
119
114
|
end
|
@@ -30,6 +30,9 @@ module FriendlyId
|
|
30
30
|
# The default configuration options.
|
31
31
|
attr_reader :defaults
|
32
32
|
|
33
|
+
# The modules in use
|
34
|
+
attr_reader :modules
|
35
|
+
|
33
36
|
# The model class that this configuration belongs to.
|
34
37
|
# @return ActiveRecord::Base
|
35
38
|
attr_accessor :model_class
|
@@ -37,6 +40,7 @@ module FriendlyId
|
|
37
40
|
def initialize(model_class, values = nil)
|
38
41
|
@model_class = model_class
|
39
42
|
@defaults = {}
|
43
|
+
@modules = []
|
40
44
|
set values
|
41
45
|
end
|
42
46
|
|
@@ -59,9 +63,15 @@ module FriendlyId
|
|
59
63
|
modules.to_a.flatten.compact.map do |object|
|
60
64
|
mod = object.kind_of?(Module) ? object : FriendlyId.const_get(object.to_s.classify)
|
61
65
|
model_class.send(:include, mod)
|
66
|
+
@modules << mod.name.split("::").last.downcase.to_sym if mod.name.present?
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
70
|
+
# Returns whether the given module is in use
|
71
|
+
def uses?(modul)
|
72
|
+
@modules.include?(modul)
|
73
|
+
end
|
74
|
+
|
65
75
|
# The column that FriendlyId will use to find the record when querying by
|
66
76
|
# friendly id.
|
67
77
|
#
|
data/lib/friendly_id/history.rb
CHANGED
@@ -59,7 +59,6 @@ method.
|
|
59
59
|
# Configures the model instance to use the History add-on.
|
60
60
|
def self.included(model_class)
|
61
61
|
model_class.instance_eval do
|
62
|
-
raise "FriendlyId::History is incompatible with FriendlyId::Scoped" if self < Scoped
|
63
62
|
@friendly_id_config.use :slugged
|
64
63
|
has_many :slugs, :as => :sluggable, :dependent => :destroy,
|
65
64
|
:class_name => Slug.to_s, :order => "#{Slug.quoted_table_name}.id DESC"
|
@@ -80,6 +79,7 @@ method.
|
|
80
79
|
relation.delete_all unless result.empty?
|
81
80
|
slugs.create! do |record|
|
82
81
|
record.slug = friendly_id
|
82
|
+
record.scope = serialized_scope if friendly_id_config.uses?(:scoped)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -90,7 +90,7 @@ method.
|
|
90
90
|
def find_one(id)
|
91
91
|
return super(id) if id.unfriendly_id?
|
92
92
|
where(@klass.friendly_id_config.query_field => id).first or
|
93
|
-
with_old_friendly_id(id) {|x|
|
93
|
+
with_old_friendly_id(id) {|x| where(:id => x).first} or
|
94
94
|
find_one_without_friendly_id(id)
|
95
95
|
end
|
96
96
|
|
@@ -98,7 +98,7 @@ method.
|
|
98
98
|
def exists?(id = false)
|
99
99
|
return super if id.unfriendly_id?
|
100
100
|
exists_without_friendly_id?(@klass.friendly_id_config.query_field => id) or
|
101
|
-
with_old_friendly_id(id) {|x| exists_without_friendly_id?(x)} or
|
101
|
+
with_old_friendly_id(id) {|x| exists_without_friendly_id?(:id => x)} or
|
102
102
|
exists_without_friendly_id?(id)
|
103
103
|
end
|
104
104
|
|
@@ -108,8 +108,8 @@ method.
|
|
108
108
|
def with_old_friendly_id(slug, &block)
|
109
109
|
sql = "SELECT sluggable_id FROM #{Slug.quoted_table_name} WHERE sluggable_type = %s AND slug = %s"
|
110
110
|
sql = sql % [@klass.base_class.to_s, slug].map {|x| connection.quote(x)}
|
111
|
-
|
112
|
-
yield
|
111
|
+
sluggable_ids = connection.select_values(sql)
|
112
|
+
yield sluggable_ids if sluggable_ids
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
@@ -127,7 +127,9 @@ method.
|
|
127
127
|
scope = Slug.where("slug = ? OR slug LIKE ?", normalized, wildcard)
|
128
128
|
scope = scope.where(:sluggable_type => sluggable_class.to_s)
|
129
129
|
scope = scope.where("sluggable_id <> ?", value) unless sluggable.new_record?
|
130
|
-
|
130
|
+
if sluggable.friendly_id_config.uses?(:scoped)
|
131
|
+
scope = scope.where("scope = ?", sluggable.serialized_scope)
|
132
|
+
end
|
131
133
|
length_command = "LENGTH"
|
132
134
|
length_command = "LEN" if sluggable.connection.adapter_name =~ /sqlserver/i
|
133
135
|
scope.order("#{length_command}(slug) DESC, slug DESC")
|
@@ -5,10 +5,12 @@ class CreateFriendlyIdSlugs < ActiveRecord::Migration
|
|
5
5
|
t.string :slug, :null => false
|
6
6
|
t.integer :sluggable_id, :null => false
|
7
7
|
t.string :sluggable_type, :limit => 40
|
8
|
+
t.string :scope
|
8
9
|
t.datetime :created_at
|
9
10
|
end
|
10
11
|
add_index :friendly_id_slugs, :sluggable_id
|
11
|
-
add_index :friendly_id_slugs, [:slug, :sluggable_type]
|
12
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type]
|
13
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], :unique => true
|
12
14
|
add_index :friendly_id_slugs, :sluggable_type
|
13
15
|
end
|
14
16
|
|
data/lib/friendly_id/scoped.rb
CHANGED
@@ -33,28 +33,6 @@ Without :scoped in this case, one of the restaurants would have the slug
|
|
33
33
|
The value for the +:scope+ option can be the name of a +belongs_to+ relation, or
|
34
34
|
a column.
|
35
35
|
|
36
|
-
Additionally, the +:scope+ option can receive an array of scope values:
|
37
|
-
|
38
|
-
class Cuisine < ActiveRecord::Base
|
39
|
-
extend FriendlyId
|
40
|
-
has_many :restaurants
|
41
|
-
friendly_id :name, :use => :slugged
|
42
|
-
end
|
43
|
-
|
44
|
-
class City < ActiveRecord::Base
|
45
|
-
extend FriendlyId
|
46
|
-
has_many :restaurants
|
47
|
-
friendly_id :name, :use => :slugged
|
48
|
-
end
|
49
|
-
|
50
|
-
class Restaurant < ActiveRecord::Base
|
51
|
-
extend FriendlyId
|
52
|
-
belongs_to :city
|
53
|
-
friendly_id :name, :use => :scoped, :scope => [:city, :cuisine]
|
54
|
-
end
|
55
|
-
|
56
|
-
All supplied values will be used to determine scope.
|
57
|
-
|
58
36
|
=== Finding Records by Friendly ID
|
59
37
|
|
60
38
|
If you are using scopes your friendly ids may not be unique, so a simple find
|
@@ -108,13 +86,16 @@ an example of one way to set this up:
|
|
108
86
|
# feature.
|
109
87
|
def self.included(model_class)
|
110
88
|
model_class.instance_eval do
|
111
|
-
raise "FriendlyId::Scoped is incompatibe with FriendlyId::History" if self < History
|
112
89
|
include Slugged unless self < Slugged
|
113
90
|
friendly_id_config.class.send :include, Configuration
|
114
91
|
friendly_id_config.slug_generator_class.send :include, SlugGenerator
|
115
92
|
end
|
116
93
|
end
|
117
94
|
|
95
|
+
def serialized_scope
|
96
|
+
friendly_id_config.scope_columns.sort.map { |column| "#{column}:#{send(column)}" }.join(",")
|
97
|
+
end
|
98
|
+
|
118
99
|
# This module adds the +:scope+ configuration option to
|
119
100
|
# {FriendlyId::Configuration FriendlyId::Configuration}.
|
120
101
|
module Configuration
|
@@ -159,12 +140,18 @@ an example of one way to set this up:
|
|
159
140
|
private
|
160
141
|
|
161
142
|
def conflict
|
162
|
-
|
163
|
-
|
164
|
-
|
143
|
+
if friendly_id_config.uses?(:history)
|
144
|
+
# When using the :history module +conflicts+ already returns only real conflicts, so there's no need to check
|
145
|
+
# for the scope columns again
|
146
|
+
conflicts.first
|
147
|
+
else
|
148
|
+
columns = friendly_id_config.scope_columns
|
149
|
+
matched = columns.inject(conflicts) do |memo, column|
|
150
|
+
memo.where(column => sluggable.send(column))
|
151
|
+
end
|
152
|
+
|
153
|
+
matched.first
|
165
154
|
end
|
166
|
-
|
167
|
-
matched.first
|
168
155
|
end
|
169
156
|
end
|
170
157
|
end
|
data/lib/friendly_id/slug.rb
CHANGED
data/test/helper.rb
CHANGED
data/test/history_test.rb
CHANGED
@@ -78,17 +78,6 @@ class HistoryTest < MiniTest::Unit::TestCase
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
|
82
|
-
test "should raise error if used with scoped" do
|
83
|
-
model_class = Class.new(ActiveRecord::Base) do
|
84
|
-
self.abstract_class = true
|
85
|
-
extend FriendlyId
|
86
|
-
end
|
87
|
-
assert_raises RuntimeError do
|
88
|
-
model_class.friendly_id :name, :use => [:history, :scoped]
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
81
|
test "should handle renames" do
|
93
82
|
with_instance_of(model_class) do |record|
|
94
83
|
record.name = 'x'
|
@@ -132,20 +121,6 @@ class HistoryTest < MiniTest::Unit::TestCase
|
|
132
121
|
end
|
133
122
|
end
|
134
123
|
|
135
|
-
test 'should name table according to prefix and suffix' do
|
136
|
-
transaction do
|
137
|
-
begin
|
138
|
-
prefix = "prefix_"
|
139
|
-
without_prefix = FriendlyId::Slug.table_name
|
140
|
-
ActiveRecord::Base.table_name_prefix = prefix
|
141
|
-
FriendlyId::Slug.reset_table_name
|
142
|
-
assert_equal prefix + without_prefix, FriendlyId::Slug.table_name
|
143
|
-
ensure
|
144
|
-
ActiveRecord::Base.table_name_prefix = ""
|
145
|
-
FriendlyId::Slug.table_name = without_prefix
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
124
|
end
|
150
125
|
|
151
126
|
class HistoryTestWithSti < HistoryTest
|
@@ -161,3 +136,67 @@ class HistoryTestWithSti < HistoryTest
|
|
161
136
|
Editorialist
|
162
137
|
end
|
163
138
|
end
|
139
|
+
|
140
|
+
|
141
|
+
|
142
|
+
class City < ActiveRecord::Base
|
143
|
+
has_many :restaurants
|
144
|
+
end
|
145
|
+
|
146
|
+
class Restaurant < ActiveRecord::Base
|
147
|
+
extend FriendlyId
|
148
|
+
belongs_to :city
|
149
|
+
friendly_id :name, :use => [:history, :scoped], :scope => :city
|
150
|
+
end
|
151
|
+
|
152
|
+
class ScopedHistoryTest < MiniTest::Unit::TestCase
|
153
|
+
include FriendlyId::Test
|
154
|
+
include FriendlyId::Test::Shared::Core
|
155
|
+
|
156
|
+
def model_class
|
157
|
+
Restaurant
|
158
|
+
end
|
159
|
+
|
160
|
+
test "should find old scoped slugs" do
|
161
|
+
city = City.create!
|
162
|
+
with_instance_of(Restaurant) do |record|
|
163
|
+
record.city = city
|
164
|
+
|
165
|
+
record.name = "x"
|
166
|
+
record.save!
|
167
|
+
|
168
|
+
record.name = "y"
|
169
|
+
record.save!
|
170
|
+
|
171
|
+
assert_equal city.restaurants.find("x"), city.restaurants.find("y")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
test "should consider old scoped slugs when creating slugs" do
|
176
|
+
city = City.create!
|
177
|
+
with_instance_of(Restaurant) do |record|
|
178
|
+
record.city = city
|
179
|
+
|
180
|
+
record.name = "x"
|
181
|
+
record.save!
|
182
|
+
|
183
|
+
record.name = "y"
|
184
|
+
record.save!
|
185
|
+
|
186
|
+
second_record = model_class.create! :city => city, :name => 'x'
|
187
|
+
assert_equal "x--2", second_record.friendly_id
|
188
|
+
|
189
|
+
third_record = model_class.create! :city => city, :name => 'y'
|
190
|
+
assert_equal "y--2", third_record.friendly_id
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
test "should allow equal slugs in different scopes" do
|
195
|
+
city = City.create!
|
196
|
+
second_city = City.create!
|
197
|
+
record = model_class.create! :city => city, :name => 'x'
|
198
|
+
second_record = model_class.create! :city => second_city, :name => 'x'
|
199
|
+
|
200
|
+
assert_equal record.slug, second_record.slug
|
201
|
+
end
|
202
|
+
end
|
data/test/schema.rb
CHANGED
@@ -34,6 +34,10 @@ module FriendlyId
|
|
34
34
|
add_index table_name, :slug, :unique => true
|
35
35
|
end
|
36
36
|
|
37
|
+
scoped_tables.each do |table_name|
|
38
|
+
add_column table_name, :slug, :string
|
39
|
+
end
|
40
|
+
|
37
41
|
# This will be used to test scopes
|
38
42
|
add_column :novels, :novelist_id, :integer
|
39
43
|
add_column :novels, :publisher_id, :integer
|
@@ -57,6 +61,9 @@ module FriendlyId
|
|
57
61
|
# This will be used to test relationships
|
58
62
|
add_column :books, :author_id, :integer
|
59
63
|
|
64
|
+
# Used to test :scoped and :history together
|
65
|
+
add_column :restaurants, :city_id, :integer
|
66
|
+
|
60
67
|
@done = true
|
61
68
|
end
|
62
69
|
|
@@ -66,12 +73,16 @@ module FriendlyId
|
|
66
73
|
%w[journalists articles novelists novels manuals translated_articles]
|
67
74
|
end
|
68
75
|
|
76
|
+
def scoped_tables
|
77
|
+
["restaurants"]
|
78
|
+
end
|
79
|
+
|
69
80
|
def simple_tables
|
70
|
-
%w[authors books publishers]
|
81
|
+
%w[authors books publishers cities]
|
71
82
|
end
|
72
83
|
|
73
84
|
def tables
|
74
|
-
simple_tables + slugged_tables
|
85
|
+
simple_tables + slugged_tables + scoped_tables
|
75
86
|
end
|
76
87
|
end
|
77
88
|
end
|
data/test/scoped_test.rb
CHANGED
@@ -54,17 +54,6 @@ class ScopedTest < MiniTest::Unit::TestCase
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
test "should raise error if used with history" do
|
58
|
-
model_class = Class.new(ActiveRecord::Base) do
|
59
|
-
self.abstract_class = true
|
60
|
-
extend FriendlyId
|
61
|
-
end
|
62
|
-
|
63
|
-
assert_raises RuntimeError do
|
64
|
-
model_class.friendly_id :name, :use => [:scoped, :history]
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
57
|
test "should apply scope with multiple columns" do
|
69
58
|
transaction do
|
70
59
|
novelist = Novelist.create! :name => "a"
|
data/test/slugged_test.rb
CHANGED
@@ -129,12 +129,6 @@ class SlugGeneratorTest < MiniTest::Unit::TestCase
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
-
test "should correctly sequence slugs that start with numbers" do
|
133
|
-
record1 = model_class.create! :name => '24-hour-testing'
|
134
|
-
assert_equal '24-hour-testing', record1.slug
|
135
|
-
record2 = model_class.create! :name => '24-hour-testing'
|
136
|
-
assert_equal '24-hour-testing--2', record2.slug
|
137
|
-
end
|
138
132
|
end
|
139
133
|
|
140
134
|
class SlugSeparatorTest < MiniTest::Unit::TestCase
|
metadata
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: friendly_id
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.1.0.beta.1
|
5
|
+
prerelease: 6
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Norman Clarke
|
@@ -9,164 +10,176 @@ authors:
|
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2013-
|
13
|
+
date: 2013-01-09 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
+
name: railties
|
16
17
|
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
17
19
|
requirements:
|
18
|
-
- -
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '3.0'
|
21
|
-
- - <
|
20
|
+
- - ~>
|
22
21
|
- !ruby/object:Gem::Version
|
23
|
-
version:
|
24
|
-
type: :
|
22
|
+
version: 3.2.0
|
23
|
+
type: :development
|
25
24
|
prerelease: false
|
26
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
27
|
requirements:
|
28
|
-
- -
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: '3.0'
|
31
|
-
- - <
|
28
|
+
- - ~>
|
32
29
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
30
|
+
version: 3.2.0
|
34
31
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
32
|
+
name: activerecord
|
36
33
|
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
37
35
|
requirements:
|
38
|
-
- -
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '3.0'
|
41
|
-
- - <
|
36
|
+
- - ~>
|
42
37
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
38
|
+
version: 3.2.0
|
44
39
|
type: :development
|
45
40
|
prerelease: false
|
46
41
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
47
43
|
requirements:
|
48
|
-
- -
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version: '3.0'
|
51
|
-
- - <
|
44
|
+
- - ~>
|
52
45
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
46
|
+
version: 3.2.0
|
54
47
|
- !ruby/object:Gem::Dependency
|
55
48
|
name: minitest
|
56
49
|
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
57
51
|
requirements:
|
58
|
-
- -
|
52
|
+
- - '='
|
59
53
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
54
|
+
version: 3.2.0
|
61
55
|
type: :development
|
62
56
|
prerelease: false
|
63
57
|
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
64
59
|
requirements:
|
65
|
-
- -
|
60
|
+
- - '='
|
66
61
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
62
|
+
version: 3.2.0
|
68
63
|
- !ruby/object:Gem::Dependency
|
69
64
|
name: mocha
|
70
65
|
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
71
67
|
requirements:
|
72
|
-
- -
|
68
|
+
- - ! '>='
|
73
69
|
- !ruby/object:Gem::Version
|
74
|
-
version: 0
|
70
|
+
version: '0'
|
75
71
|
type: :development
|
76
72
|
prerelease: false
|
77
73
|
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
78
75
|
requirements:
|
79
|
-
- -
|
76
|
+
- - ! '>='
|
80
77
|
- !ruby/object:Gem::Version
|
81
|
-
version: 0
|
78
|
+
version: '0'
|
82
79
|
- !ruby/object:Gem::Dependency
|
83
80
|
name: maruku
|
84
81
|
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
85
83
|
requirements:
|
86
|
-
- - '>='
|
84
|
+
- - ! '>='
|
87
85
|
- !ruby/object:Gem::Version
|
88
86
|
version: '0'
|
89
87
|
type: :development
|
90
88
|
prerelease: false
|
91
89
|
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
92
91
|
requirements:
|
93
|
-
- - '>='
|
92
|
+
- - ! '>='
|
94
93
|
- !ruby/object:Gem::Version
|
95
94
|
version: '0'
|
96
95
|
- !ruby/object:Gem::Dependency
|
97
96
|
name: yard
|
98
97
|
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
99
|
requirements:
|
100
|
-
- - '>='
|
100
|
+
- - ! '>='
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: '0'
|
103
103
|
type: :development
|
104
104
|
prerelease: false
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
106
107
|
requirements:
|
107
|
-
- - '>='
|
108
|
+
- - ! '>='
|
108
109
|
- !ruby/object:Gem::Version
|
109
110
|
version: '0'
|
110
111
|
- !ruby/object:Gem::Dependency
|
111
112
|
name: i18n
|
112
113
|
requirement: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
113
115
|
requirements:
|
114
|
-
- - '>='
|
116
|
+
- - ! '>='
|
115
117
|
- !ruby/object:Gem::Version
|
116
118
|
version: '0'
|
117
119
|
type: :development
|
118
120
|
prerelease: false
|
119
121
|
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
120
123
|
requirements:
|
121
|
-
- - '>='
|
124
|
+
- - ! '>='
|
122
125
|
- !ruby/object:Gem::Version
|
123
126
|
version: '0'
|
124
127
|
- !ruby/object:Gem::Dependency
|
125
128
|
name: ffaker
|
126
129
|
requirement: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
127
131
|
requirements:
|
128
|
-
- - '>='
|
132
|
+
- - ! '>='
|
129
133
|
- !ruby/object:Gem::Version
|
130
134
|
version: '0'
|
131
135
|
type: :development
|
132
136
|
prerelease: false
|
133
137
|
version_requirements: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
134
139
|
requirements:
|
135
|
-
- - '>='
|
140
|
+
- - ! '>='
|
136
141
|
- !ruby/object:Gem::Version
|
137
142
|
version: '0'
|
138
143
|
- !ruby/object:Gem::Dependency
|
139
144
|
name: simplecov
|
140
145
|
requirement: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
141
147
|
requirements:
|
142
|
-
- - '>='
|
148
|
+
- - ! '>='
|
143
149
|
- !ruby/object:Gem::Version
|
144
150
|
version: '0'
|
145
151
|
type: :development
|
146
152
|
prerelease: false
|
147
153
|
version_requirements: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
148
155
|
requirements:
|
149
|
-
- - '>='
|
156
|
+
- - ! '>='
|
150
157
|
- !ruby/object:Gem::Version
|
151
158
|
version: '0'
|
152
159
|
- !ruby/object:Gem::Dependency
|
153
160
|
name: globalize3
|
154
161
|
requirement: !ruby/object:Gem::Requirement
|
162
|
+
none: false
|
155
163
|
requirements:
|
156
|
-
- - '>='
|
164
|
+
- - ! '>='
|
157
165
|
- !ruby/object:Gem::Version
|
158
166
|
version: '0'
|
159
167
|
type: :development
|
160
168
|
prerelease: false
|
161
169
|
version_requirements: !ruby/object:Gem::Requirement
|
170
|
+
none: false
|
162
171
|
requirements:
|
163
|
-
- - '>='
|
172
|
+
- - ! '>='
|
164
173
|
- !ruby/object:Gem::Version
|
165
174
|
version: '0'
|
166
|
-
description:
|
167
|
-
|
175
|
+
description: ! 'FriendlyId is the "Swiss Army bulldozer" of slugging and permalink
|
176
|
+
plugins for
|
177
|
+
|
168
178
|
Ruby on Rails. It allows you to create pretty URLs and work with human-friendly
|
179
|
+
|
169
180
|
strings as if they were numeric ids for Active Record models.
|
181
|
+
|
182
|
+
'
|
170
183
|
email:
|
171
184
|
- norman@njclarke.com
|
172
185
|
- parndt@gmail.com
|
@@ -191,7 +204,6 @@ files:
|
|
191
204
|
- gemfiles/Gemfile.rails-3.1.rb
|
192
205
|
- gemfiles/Gemfile.rails-3.2.rb
|
193
206
|
- lib/friendly_id.rb
|
194
|
-
- lib/friendly_id/.gitattributes
|
195
207
|
- lib/friendly_id/base.rb
|
196
208
|
- lib/friendly_id/configuration.rb
|
197
209
|
- lib/friendly_id/finder_methods.rb
|
@@ -205,7 +217,6 @@ files:
|
|
205
217
|
- lib/friendly_id/slug.rb
|
206
218
|
- lib/friendly_id/slug_generator.rb
|
207
219
|
- lib/friendly_id/slugged.rb
|
208
|
-
- lib/friendly_id/version.rb
|
209
220
|
- lib/generators/friendly_id_generator.rb
|
210
221
|
- test/base_test.rb
|
211
222
|
- test/compatibility/ancestry/Gemfile
|
@@ -229,33 +240,37 @@ files:
|
|
229
240
|
- test/slugged_test.rb
|
230
241
|
- test/sti_test.rb
|
231
242
|
homepage: http://github.com/norman/friendly_id
|
232
|
-
licenses:
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
NOTE: FriendlyId 4.x breaks compatibility with 3.x. If you're upgrading
|
243
|
+
licenses: []
|
244
|
+
post_install_message: ! 'NOTE: FriendlyId 4.x breaks compatibility with 3.x. If you''re
|
245
|
+
upgrading
|
246
|
+
|
237
247
|
from 3.x, please see this document:
|
238
248
|
|
249
|
+
|
239
250
|
http://rubydoc.info/github/norman/friendly_id/master/file/WhatsNew.md
|
240
251
|
|
252
|
+
|
253
|
+
'
|
241
254
|
rdoc_options: []
|
242
255
|
require_paths:
|
243
256
|
- lib
|
244
257
|
required_ruby_version: !ruby/object:Gem::Requirement
|
258
|
+
none: false
|
245
259
|
requirements:
|
246
|
-
- - '>='
|
260
|
+
- - ! '>='
|
247
261
|
- !ruby/object:Gem::Version
|
248
262
|
version: '0'
|
249
263
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
264
|
+
none: false
|
250
265
|
requirements:
|
251
|
-
- - '
|
266
|
+
- - ! '>'
|
252
267
|
- !ruby/object:Gem::Version
|
253
|
-
version:
|
268
|
+
version: 1.3.1
|
254
269
|
requirements: []
|
255
270
|
rubyforge_project: friendly_id
|
256
|
-
rubygems_version:
|
271
|
+
rubygems_version: 1.8.24
|
257
272
|
signing_key:
|
258
|
-
specification_version:
|
273
|
+
specification_version: 3
|
259
274
|
summary: A comprehensive slugging and pretty-URL plugin.
|
260
275
|
test_files: []
|
261
276
|
has_rdoc:
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 9fbc5031a53b7d9a5ccd504f5ae0320b438ae54c
|
4
|
-
data.tar.gz: 4762396921c1d48229e84b3a2c3641a0910606e1
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: 626640c8d2daadc57079407bed1e692caf7c3e0c7f7768a8cab195cfbe1d274d0f0220cea71c5413f0293174ba769fb6e809f537e34285717aed4fb2f3d171c2
|
7
|
-
data.tar.gz: e27071a087add84317bcc85be519d070e00e9ada3fe77cc123234bbd4ac33cff258cb41bed593d9cca01330ab80f217bde9765720cc5d77187f7aa6e6341cb82
|
@@ -1 +0,0 @@
|
|
1
|
-
version.rb merge=ours
|
data/lib/friendly_id/version.rb
DELETED