friendly_id 4.0.10.1 → 4.1.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- 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