friendly_id 5.2.2 → 5.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -0
- data/.github/stale.yml +17 -0
- data/.github/workflows/test.yml +60 -0
- data/Changelog.md +39 -1
- data/Gemfile +3 -0
- data/README.md +54 -164
- data/Rakefile +2 -2
- data/UPGRADING.md +115 -0
- data/certs/parndt.pem +25 -0
- data/friendly_id.gemspec +9 -5
- data/gemfiles/Gemfile.rails-5.0.rb +2 -2
- data/gemfiles/{Gemfile.rails-4.2.rb → Gemfile.rails-5.1.rb} +4 -5
- data/gemfiles/{Gemfile.rails-4.1.rb → Gemfile.rails-5.2.rb} +5 -7
- data/gemfiles/{Gemfile.rails-4.0.rb → Gemfile.rails-6.0.rb} +5 -8
- data/lib/friendly_id/base.rb +4 -8
- data/lib/friendly_id/candidates.rb +0 -2
- data/lib/friendly_id/configuration.rb +3 -2
- data/lib/friendly_id/finder_methods.rb +18 -7
- data/lib/friendly_id/finders.rb +1 -1
- data/lib/friendly_id/history.rb +21 -12
- data/lib/friendly_id/initializer.rb +11 -0
- data/lib/friendly_id/migration.rb +9 -3
- data/lib/friendly_id/object_utils.rb +9 -2
- data/lib/friendly_id/reserved.rb +1 -0
- data/lib/friendly_id/scoped.rb +9 -2
- data/lib/friendly_id/sequentially_slugged.rb +12 -2
- data/lib/friendly_id/slug.rb +4 -0
- data/lib/friendly_id/slug_generator.rb +6 -1
- data/lib/friendly_id/slugged.rb +3 -3
- data/lib/friendly_id/version.rb +1 -1
- data/test/databases.yml +6 -4
- data/test/finders_test.rb +24 -0
- data/test/helper.rb +13 -3
- data/test/history_test.rb +86 -7
- data/test/numeric_slug_test.rb +31 -0
- data/test/object_utils_test.rb +5 -3
- data/test/reserved_test.rb +10 -0
- data/test/schema.rb +19 -2
- data/test/scoped_test.rb +13 -0
- data/test/sequentially_slugged_test.rb +59 -0
- data/test/shared.rb +4 -4
- data/test/simple_i18n_test.rb +2 -2
- data/test/slugged_test.rb +168 -4
- metadata +48 -19
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -40
data/UPGRADING.md
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
## Articles
|
2
|
+
|
3
|
+
* [Migrating an ad-hoc URL slug system to FriendlyId](http://olivierlacan.com/posts/migrating-an-ad-hoc-url-slug-system-to-friendly-id/)
|
4
|
+
* [Pretty URLs with FriendlyId](http://railscasts.com/episodes/314-pretty-urls-with-friendlyid)
|
5
|
+
|
6
|
+
## Docs
|
7
|
+
|
8
|
+
The most current docs from the master branch can always be found
|
9
|
+
[here](http://norman.github.io/friendly_id).
|
10
|
+
|
11
|
+
Docs for older versions are also available:
|
12
|
+
|
13
|
+
* [5.0](http://norman.github.io/friendly_id/5.0/)
|
14
|
+
* [4.0](http://norman.github.io/friendly_id/4.0/)
|
15
|
+
* [3.3](http://norman.github.io/friendly_id/3.3/)
|
16
|
+
* [2.3](http://norman.github.io/friendly_id/2.3/)
|
17
|
+
|
18
|
+
## What Changed in Version 5.1
|
19
|
+
|
20
|
+
5.1 is a bugfix release, but bumps the minor version because some applications may be dependent
|
21
|
+
on the previously buggy behavior. The changes include:
|
22
|
+
|
23
|
+
* Blank strings can no longer be used as slugs.
|
24
|
+
* When the first slug candidate is rejected because it is reserved, additional candidates will
|
25
|
+
now be considered before marking the record as invalid.
|
26
|
+
* The `:finders` module is now compatible with Rails 4.2.
|
27
|
+
|
28
|
+
## What Changed in Version 5.0
|
29
|
+
|
30
|
+
As of version 5.0, FriendlyId uses [semantic versioning](http://semver.org/). Therefore, as you might
|
31
|
+
infer from the version number, 5.0 introduces changes incompatible with 4.0.
|
32
|
+
|
33
|
+
The most important changes are:
|
34
|
+
|
35
|
+
* Finders are no longer overridden by default. If you want to do friendly finds,
|
36
|
+
you must do `Model.friendly.find` rather than `Model.find`. You can however
|
37
|
+
restore FriendlyId 4-style finders by using the `:finders` addon:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
friendly_id :foo, use: :slugged # you must do MyClass.friendly.find('bar')
|
41
|
+
# or...
|
42
|
+
friendly_id :foo, use: [:slugged, :finders] # you can now do MyClass.find('bar')
|
43
|
+
```
|
44
|
+
* A new "candidates" functionality which makes it easy to set up a list of
|
45
|
+
alternate slugs that can be used to uniquely distinguish records, rather than
|
46
|
+
appending a sequence. For example:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
class Restaurant < ActiveRecord::Base
|
50
|
+
extend FriendlyId
|
51
|
+
friendly_id :slug_candidates, use: :slugged
|
52
|
+
|
53
|
+
# Try building a slug based on the following fields in
|
54
|
+
# increasing order of specificity.
|
55
|
+
def slug_candidates
|
56
|
+
[
|
57
|
+
:name,
|
58
|
+
[:name, :city],
|
59
|
+
[:name, :street, :city],
|
60
|
+
[:name, :street_number, :street, :city]
|
61
|
+
]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
```
|
65
|
+
* Now that candidates have been added, FriendlyId no longer uses a numeric
|
66
|
+
sequence to differentiate conflicting slug, but rather a UUID (e.g. something
|
67
|
+
like `2bc08962-b3dd-4f29-b2e6-244710c86106`). This makes the
|
68
|
+
codebase simpler and more reliable when running concurrently, at the expense
|
69
|
+
of uglier ids being generated when there are conflicts.
|
70
|
+
* The default sequence separator has been changed from two dashes to one dash.
|
71
|
+
* Slugs are no longer regenerated when a record is saved. If you want to regenerate
|
72
|
+
a slug, you must explicitly set the slug column to nil:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
restaurant.friendly_id # joes-diner
|
76
|
+
restaurant.name = "The Plaza Diner"
|
77
|
+
restaurant.save!
|
78
|
+
restaurant.friendly_id # joes-diner
|
79
|
+
restaurant.slug = nil
|
80
|
+
restaurant.save!
|
81
|
+
restaurant.friendly_id # the-plaza-diner
|
82
|
+
```
|
83
|
+
|
84
|
+
You can restore some of the old behavior by overriding the
|
85
|
+
`should_generate_new_friendly_id?` method.
|
86
|
+
* The `friendly_id` Rails generator now generates an initializer showing you
|
87
|
+
how to do some common global configuration.
|
88
|
+
* The Globalize plugin has moved to a [separate gem](https://github.com/norman/friendly_id-globalize) (currently in alpha).
|
89
|
+
* The `:reserved` module no longer includes any default reserved words.
|
90
|
+
Previously it blocked "edit" and "new" everywhere. The default word list has
|
91
|
+
been moved to `config/initializers/friendly_id.rb` and now includes many more
|
92
|
+
words.
|
93
|
+
* The `:history` and `:scoped` addons can now be used together.
|
94
|
+
* Since it now requires Rails 4, FriendlyId also now requires Ruby 1.9.3 or
|
95
|
+
higher.
|
96
|
+
|
97
|
+
## Upgrading from FriendlyId 4.0
|
98
|
+
|
99
|
+
Run `rails generate friendly_id --skip-migration` and edit the initializer
|
100
|
+
generated in `config/initializers/friendly_id.rb`. This file contains notes
|
101
|
+
describing how to restore (or not) some of the defaults from FriendlyId 4.0.
|
102
|
+
|
103
|
+
If you want to use the `:history` and `:scoped` addons together, you must add a
|
104
|
+
`:scope` column to your friendly_id_slugs table and replace the unique index on
|
105
|
+
`:slug` and `:sluggable_type` with a unique index on those two columns, plus
|
106
|
+
the new `:scope` column.
|
107
|
+
|
108
|
+
A migration like this should be sufficient:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
add_column :friendly_id_slugs, :scope, :string
|
112
|
+
remove_index :friendly_id_slugs, [:slug, :sluggable_type]
|
113
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type]
|
114
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], unique: true
|
115
|
+
```
|
data/certs/parndt.pem
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIEMjCCApqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhnZW1z
|
3
|
+
L0RDPXAvREM9YXJuZHQvREM9aW8wHhcNMjAwNTEwMjIxOTQ2WhcNMjEwNTEwMjIx
|
4
|
+
OTQ2WjAjMSEwHwYDVQQDDBhnZW1zL0RDPXAvREM9YXJuZHQvREM9aW8wggGiMA0G
|
5
|
+
CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDT+JzHYPGMYJt9ct2DCsbIymn1uJJp
|
6
|
+
HnDkQESfsGe40jTC90oF2iVbVOkaacNc1N3CSWUZvZjuygUuS86P6/kpBILGdO2+
|
7
|
+
bkXXKtfGC2YGGx9TdNLpCb4925vQHvdFeKXGpQDZdDw1SNC6zraZou47CvOE1cl2
|
8
|
+
Bp+1QMZuGRZ4+5CzOEWDWurjqce3O1jUEbyBB7z5H0h/YEaxfXipxhL1Dhi0sgkH
|
9
|
+
qP/e6SxzifdifdZCksJFQ06a1ji9hJY6eM23qbv/aaluVHAZSVBAQBS7rYniLo+N
|
10
|
+
G4vpFhoubQO5u8UluUtCaPUpI/qOvVcSaZn3ZkzlMwC8b1RwAeXBQmtFE2wnrv2i
|
11
|
+
ovTwoN7rHchwhgaHbkuFh4Wr92wGbrWL7J+X8rWKk1f8RF4kvtNE/NA6YrkxTpVh
|
12
|
+
QMyDmekt7rTxvcq2NneLGroWIUVCx/JID+Jw492LKQ6Sl1/P2TRzdEDtqZAZL0gt
|
13
|
+
xlWeMUfGG2D/gLnhs5qnaFaWQwGTmBnTgHcCAwEAAaNxMG8wCQYDVR0TBAIwADAL
|
14
|
+
BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFEqtAyQVxPgKsrgoTQ1YmaIu/fmvMBoGA1Ud
|
15
|
+
EQQTMBGBD2dlbXNAcC5hcm5kdC5pbzAaBgNVHRIEEzARgQ9nZW1zQHAuYXJuZHQu
|
16
|
+
aW8wDQYJKoZIhvcNAQELBQADggGBALu2HM50B8xqlAXkCwavJDvWWtV9pG1igFUg
|
17
|
+
friZRWprUQ5nTaNmAd8p8qbJQwaIK2gt+DfYWfB9LtKnQTfbhLRBbmJ7zYw8LjKY
|
18
|
+
PwCs4RWjDAiuyCO3ppfsz+1bsMUXPLgWlaUkXsUy3nr2NruEFTO9zu3wGYQQ93Tt
|
19
|
+
vYSHOnP35UB4QjsjNrOO7FBaQfy6O909PP+GnVcJ62s9c26voJz63RSolwY7Jydw
|
20
|
+
XUlG68jjJKSoDHRzVTmNB7sX8rs8P2kvYkpIUXPHyls3mWBWjBWbdEYWESZrxI2x
|
21
|
+
dS7jY3AnfqhvsWra2pSREb2IDqPnJrHVOejnEI/zuuufUxLwDx3AC6SMdsyWkZ7V
|
22
|
+
9OmLt2rg75Sct6h2220lO5ySqYtqAXuOMBDGv5L0zLalx1g8LACA7uILTKVWh8B8
|
23
|
+
Hsej0MQ3drCB1eA4c9OXdCUQJnY2aLTq3uNvTbZvoTgWK55eq3KLBJ4zzoKZ4tBX
|
24
|
+
/HIFI/fEwYlI1Ji3oikUrHkc4rWgaQ==
|
25
|
+
-----END CERTIFICATE-----
|
data/friendly_id.gemspec
CHANGED
@@ -8,20 +8,19 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.email = ["norman@njclarke.com", "p@arndt.io"]
|
9
9
|
s.homepage = "https://github.com/norman/friendly_id"
|
10
10
|
s.summary = "A comprehensive slugging and pretty-URL plugin."
|
11
|
-
s.rubyforge_project = "friendly_id"
|
12
11
|
s.files = `git ls-files`.split("\n")
|
13
12
|
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
14
13
|
s.require_paths = ["lib"]
|
15
14
|
s.license = 'MIT'
|
16
15
|
|
17
|
-
s.required_ruby_version = '>= 1.
|
16
|
+
s.required_ruby_version = '>= 2.1.0'
|
18
17
|
|
19
18
|
s.add_dependency 'activerecord', '>= 4.0.0'
|
20
19
|
|
21
20
|
s.add_development_dependency 'coveralls'
|
22
|
-
s.add_development_dependency 'railties', '
|
23
|
-
s.add_development_dependency 'minitest', '~> 5.3
|
24
|
-
s.add_development_dependency 'mocha', '~> 1.1
|
21
|
+
s.add_development_dependency 'railties', '>= 4.0'
|
22
|
+
s.add_development_dependency 'minitest', '~> 5.3'
|
23
|
+
s.add_development_dependency 'mocha', '~> 1.1'
|
25
24
|
s.add_development_dependency 'yard'
|
26
25
|
s.add_development_dependency 'i18n'
|
27
26
|
s.add_development_dependency 'ffaker'
|
@@ -32,4 +31,9 @@ FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for
|
|
32
31
|
Active Record. It lets you create pretty URLs and work with human-friendly
|
33
32
|
strings as if they were numeric ids.
|
34
33
|
EOM
|
34
|
+
|
35
|
+
s.cert_chain = [File.expand_path('certs/parndt.pem', __dir__)]
|
36
|
+
if $PROGRAM_NAME =~ /gem\z/ && ARGV.include?('build') && ARGV.include?(__FILE__)
|
37
|
+
s.signing_key = File.expand_path('~/.ssh/gem-private_key.pem')
|
38
|
+
end
|
35
39
|
end
|
@@ -9,8 +9,8 @@ gem 'i18n', '~> 0.7.0'
|
|
9
9
|
# Database Configuration
|
10
10
|
group :development, :test do
|
11
11
|
platforms :jruby do
|
12
|
-
gem 'activerecord-jdbcmysql-adapter',
|
13
|
-
gem 'activerecord-jdbcpostgresql-adapter',
|
12
|
+
gem 'activerecord-jdbcmysql-adapter', '~> 50.1'
|
13
|
+
gem 'activerecord-jdbcpostgresql-adapter', '~> 50.1'
|
14
14
|
gem 'kramdown'
|
15
15
|
end
|
16
16
|
|
@@ -2,15 +2,14 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec path: '../'
|
4
4
|
|
5
|
-
gem 'activerecord', '~>
|
6
|
-
gem 'railties', '~>
|
7
|
-
gem 'i18n', '~> 0.7.0'
|
5
|
+
gem 'activerecord', '~> 5.1.0'
|
6
|
+
gem 'railties', '~> 5.1.0'
|
8
7
|
|
9
8
|
# Database Configuration
|
10
9
|
group :development, :test do
|
11
10
|
platforms :jruby do
|
12
|
-
gem 'activerecord-jdbcmysql-adapter', '~> 1
|
13
|
-
gem 'activerecord-jdbcpostgresql-adapter', '~> 1
|
11
|
+
gem 'activerecord-jdbcmysql-adapter', '~> 50.1'
|
12
|
+
gem 'activerecord-jdbcpostgresql-adapter', '~> 50.1'
|
14
13
|
gem 'kramdown'
|
15
14
|
end
|
16
15
|
|
@@ -2,21 +2,20 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec path: '../'
|
4
4
|
|
5
|
-
gem 'activerecord', '~>
|
6
|
-
gem 'railties', '~>
|
5
|
+
gem 'activerecord', '~> 5.2.0'
|
6
|
+
gem 'railties', '~> 5.2.0'
|
7
7
|
|
8
8
|
# Database Configuration
|
9
9
|
group :development, :test do
|
10
10
|
platforms :jruby do
|
11
|
-
gem 'activerecord-
|
12
|
-
gem 'activerecord-
|
13
|
-
gem 'activerecord-jdbcpostgresql-adapter', '~> 1.3.14'
|
11
|
+
gem 'activerecord-jdbcmysql-adapter', '~> 51.1'
|
12
|
+
gem 'activerecord-jdbcpostgresql-adapter', '~> 51.1'
|
14
13
|
gem 'kramdown'
|
15
14
|
end
|
16
15
|
|
17
16
|
platforms :ruby, :rbx do
|
18
17
|
gem 'sqlite3'
|
19
|
-
gem 'mysql2'
|
18
|
+
gem 'mysql2'
|
20
19
|
gem 'pg'
|
21
20
|
gem 'redcarpet'
|
22
21
|
end
|
@@ -24,6 +23,5 @@ group :development, :test do
|
|
24
23
|
platforms :rbx do
|
25
24
|
gem 'rubysl', '~> 2.0'
|
26
25
|
gem 'rubinius-developer_tools'
|
27
|
-
gem 'json'
|
28
26
|
end
|
29
27
|
end
|
@@ -2,22 +2,20 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec path: '../'
|
4
4
|
|
5
|
-
gem 'activerecord', '~>
|
6
|
-
gem 'railties', '~>
|
7
|
-
gem 'minitest', '~> 4.5.0'
|
5
|
+
gem 'activerecord', '~> 6.0.0'
|
6
|
+
gem 'railties', '~> 6.0.0'
|
8
7
|
|
9
8
|
# Database Configuration
|
10
9
|
group :development, :test do
|
11
10
|
platforms :jruby do
|
12
|
-
gem 'activerecord-
|
13
|
-
gem 'activerecord-
|
14
|
-
gem 'activerecord-jdbcpostgresql-adapter', '~> 1.3.14'
|
11
|
+
gem 'activerecord-jdbcmysql-adapter', '~> 51.1'
|
12
|
+
gem 'activerecord-jdbcpostgresql-adapter', '~> 51.1'
|
15
13
|
gem 'kramdown'
|
16
14
|
end
|
17
15
|
|
18
16
|
platforms :ruby, :rbx do
|
19
17
|
gem 'sqlite3'
|
20
|
-
gem 'mysql2'
|
18
|
+
gem 'mysql2'
|
21
19
|
gem 'pg'
|
22
20
|
gem 'redcarpet'
|
23
21
|
end
|
@@ -25,6 +23,5 @@ group :development, :test do
|
|
25
23
|
platforms :rbx do
|
26
24
|
gem 'rubysl', '~> 2.0'
|
27
25
|
gem 'rubinius-developer_tools'
|
28
|
-
gem 'json'
|
29
26
|
end
|
30
27
|
end
|
data/lib/friendly_id/base.rb
CHANGED
@@ -159,8 +159,9 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
159
159
|
#
|
160
160
|
# @option options [Symbol,Module] :use The addon or name of an addon to use.
|
161
161
|
# By default, FriendlyId provides {FriendlyId::Slugged :slugged},
|
162
|
-
# {FriendlyId::
|
163
|
-
# {FriendlyId::
|
162
|
+
# {FriendlyId::Reserved :finders}, {FriendlyId::History :history},
|
163
|
+
# {FriendlyId::Reserved :reserved}, {FriendlyId::Scoped :scoped}, and
|
164
|
+
# {FriendlyId::SimpleI18n :simple_i18n}.
|
164
165
|
#
|
165
166
|
# @option options [Array] :reserved_words Available when using `:reserved`,
|
166
167
|
# which is loaded by default. Sets an array of words banned for use as
|
@@ -261,12 +262,7 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
261
262
|
# Either the friendly_id, or the numeric id cast to a string.
|
262
263
|
def to_param
|
263
264
|
if friendly_id_config.routes == :friendly
|
264
|
-
|
265
|
-
diff = changes[friendly_id_config.query_field]
|
266
|
-
diff.first || diff.second
|
267
|
-
else
|
268
|
-
friendly_id.presence.to_param || super
|
269
|
-
end
|
265
|
+
friendly_id.presence.to_param || super
|
270
266
|
else
|
271
267
|
super
|
272
268
|
end
|
@@ -25,6 +25,7 @@ module FriendlyId
|
|
25
25
|
attr_accessor :routes
|
26
26
|
|
27
27
|
def initialize(model_class, values = nil)
|
28
|
+
@base = nil
|
28
29
|
@model_class = model_class
|
29
30
|
@defaults = {}
|
30
31
|
@modules = []
|
@@ -47,8 +48,8 @@ module FriendlyId
|
|
47
48
|
#
|
48
49
|
# @param [#to_s,Module] modules Arguments should be Modules, or symbols or
|
49
50
|
# strings that correspond with the name of an addon to use with FriendlyId.
|
50
|
-
# By default FriendlyId provides `:slugged`, `:
|
51
|
-
# and `:scoped`.
|
51
|
+
# By default FriendlyId provides `:slugged`, `:finders`, `:history`,
|
52
|
+
# `:reserved`, `:simple_i18n`, and `:scoped`.
|
52
53
|
def use(*modules)
|
53
54
|
modules.to_a.flatten.compact.map do |object|
|
54
55
|
mod = get_module(object)
|
@@ -9,7 +9,7 @@ module FriendlyId
|
|
9
9
|
# id matching '123' and then fall back to looking for a record with the
|
10
10
|
# numeric id '123'.
|
11
11
|
#
|
12
|
-
# Since FriendlyId 5.0, if the id is a
|
12
|
+
# Since FriendlyId 5.0, if the id is a nonnumeric string like '123-foo' it
|
13
13
|
# will *only* search by friendly id and not fall back to the regular find
|
14
14
|
# method.
|
15
15
|
#
|
@@ -20,20 +20,22 @@ module FriendlyId
|
|
20
20
|
return super if args.count != 1 || id.unfriendly_id?
|
21
21
|
first_by_friendly_id(id).tap {|result| return result unless result.nil?}
|
22
22
|
return super if potential_primary_key?(id)
|
23
|
-
|
23
|
+
raise_not_found_exception id
|
24
|
+
|
24
25
|
end
|
25
26
|
|
26
27
|
# Returns true if a record with the given id exists.
|
27
28
|
def exists?(conditions = :none)
|
28
|
-
return super
|
29
|
-
exists_by_friendly_id?(conditions)
|
29
|
+
return super if conditions.unfriendly_id?
|
30
|
+
return true if exists_by_friendly_id?(conditions)
|
31
|
+
super
|
30
32
|
end
|
31
33
|
|
32
34
|
# Finds exclusively by the friendly id, completely bypassing original
|
33
35
|
# `find`.
|
34
36
|
# @raise ActiveRecord::RecordNotFound
|
35
37
|
def find_by_friendly_id(id)
|
36
|
-
first_by_friendly_id(id) or raise
|
38
|
+
first_by_friendly_id(id) or raise raise_not_found_exception(id)
|
37
39
|
end
|
38
40
|
|
39
41
|
def exists_by_friendly_id?(id)
|
@@ -50,14 +52,23 @@ module FriendlyId
|
|
50
52
|
when :integer
|
51
53
|
Integer(id, 10) rescue false
|
52
54
|
when :uuid
|
53
|
-
id.match
|
55
|
+
id.match(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
|
54
56
|
else
|
55
57
|
true
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
59
61
|
def first_by_friendly_id(id)
|
60
|
-
find_by(friendly_id_config.query_field => id)
|
62
|
+
find_by(friendly_id_config.query_field => id.downcase)
|
63
|
+
end
|
64
|
+
|
65
|
+
def raise_not_found_exception(id)
|
66
|
+
message = "can't find record with friendly id: #{id.inspect}"
|
67
|
+
if ActiveRecord.version < Gem::Version.create('5.0') then
|
68
|
+
raise ActiveRecord::RecordNotFound.new(message)
|
69
|
+
else
|
70
|
+
raise ActiveRecord::RecordNotFound.new(message, name, friendly_id_config.query_field, id)
|
71
|
+
end
|
61
72
|
end
|
62
73
|
|
63
74
|
end
|
data/lib/friendly_id/finders.rb
CHANGED
@@ -76,7 +76,7 @@ for models that use FriendlyId with something similar to the following:
|
|
76
76
|
def self.setup(model_class)
|
77
77
|
model_class.instance_eval do
|
78
78
|
relation.class.send(:include, friendly_id_config.finder_methods)
|
79
|
-
if (ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR == 2) || ActiveRecord::VERSION::MAJOR
|
79
|
+
if (ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR == 2) || ActiveRecord::VERSION::MAJOR >= 5
|
80
80
|
model_class.send(:extend, friendly_id_config.finder_methods)
|
81
81
|
end
|
82
82
|
end
|
data/lib/friendly_id/history.rb
CHANGED
@@ -44,9 +44,9 @@ method.
|
|
44
44
|
@post = Post.friendly.find params[:id]
|
45
45
|
|
46
46
|
# If an old id or a numeric id was used to find the record, then
|
47
|
-
# the request
|
48
|
-
# a 301 redirect
|
49
|
-
if
|
47
|
+
# the request slug will not match the current slug, and we should do
|
48
|
+
# a 301 redirect to the new path
|
49
|
+
if params[:id] != @post.slug
|
50
50
|
return redirect_to @post, :status => :moved_permanently
|
51
51
|
end
|
52
52
|
end
|
@@ -72,7 +72,7 @@ method.
|
|
72
72
|
# Configures the model instance to use the History add-on.
|
73
73
|
def self.included(model_class)
|
74
74
|
model_class.class_eval do
|
75
|
-
has_many :slugs, -> {order(
|
75
|
+
has_many :slugs, -> {order(id: :desc)}, **{
|
76
76
|
:as => :sluggable,
|
77
77
|
:dependent => @friendly_id_config.dependent_value,
|
78
78
|
:class_name => Slug.to_s
|
@@ -86,14 +86,13 @@ method.
|
|
86
86
|
include ::FriendlyId::FinderMethods
|
87
87
|
|
88
88
|
def exists_by_friendly_id?(id)
|
89
|
-
|
89
|
+
super || joins(:slugs).where(slug_history_clause(id)).exists?
|
90
90
|
end
|
91
91
|
|
92
92
|
private
|
93
93
|
|
94
94
|
def first_by_friendly_id(id)
|
95
|
-
|
96
|
-
matching_record || slug_table_record(id)
|
95
|
+
super || slug_table_record(id)
|
97
96
|
end
|
98
97
|
|
99
98
|
def slug_table_record(id)
|
@@ -111,9 +110,10 @@ method.
|
|
111
110
|
# to be conflicts. This will allow a record to revert to a previously
|
112
111
|
# used slug.
|
113
112
|
def scope_for_slug_generator
|
114
|
-
relation = super
|
115
|
-
|
116
|
-
|
113
|
+
relation = super.joins(:slugs)
|
114
|
+
unless new_record?
|
115
|
+
relation = relation.merge(Slug.where('sluggable_id <> ?', id))
|
116
|
+
end
|
117
117
|
if friendly_id_config.uses?(:scoped)
|
118
118
|
relation = relation.where(Slug.arel_table[:scope].eq(serialized_scope))
|
119
119
|
end
|
@@ -122,17 +122,26 @@ method.
|
|
122
122
|
|
123
123
|
def create_slug
|
124
124
|
return unless friendly_id
|
125
|
-
return if
|
125
|
+
return if history_is_up_to_date?
|
126
126
|
# Allow reversion back to a previously used slug
|
127
127
|
relation = slugs.where(:slug => friendly_id)
|
128
128
|
if friendly_id_config.uses?(:scoped)
|
129
129
|
relation = relation.where(:scope => serialized_scope)
|
130
130
|
end
|
131
|
-
relation.
|
131
|
+
relation.destroy_all unless relation.empty?
|
132
132
|
slugs.create! do |record|
|
133
133
|
record.slug = friendly_id
|
134
134
|
record.scope = serialized_scope if friendly_id_config.uses?(:scoped)
|
135
135
|
end
|
136
136
|
end
|
137
|
+
|
138
|
+
def history_is_up_to_date?
|
139
|
+
latest_history = slugs.first
|
140
|
+
check = latest_history.try(:slug) == friendly_id
|
141
|
+
if friendly_id_config.uses?(:scoped)
|
142
|
+
check = check && latest_history.scope == serialized_scope
|
143
|
+
end
|
144
|
+
check
|
145
|
+
end
|
137
146
|
end
|
138
147
|
end
|