friendly_id 5.4.1 → 5.5.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/test.yml +38 -36
- data/.yardopts +2 -0
- data/Changelog.md +15 -0
- data/Gemfile +9 -13
- data/README.md +21 -0
- data/Rakefile +24 -27
- data/bench.rb +30 -27
- data/certs/parndt.pem +25 -23
- data/friendly_id.gemspec +26 -29
- data/gemfiles/Gemfile.rails-5.2.rb +11 -16
- data/gemfiles/Gemfile.rails-6.0.rb +11 -16
- data/gemfiles/Gemfile.rails-6.1.rb +22 -0
- data/gemfiles/Gemfile.rails-7.0.rb +22 -0
- data/guide.rb +13 -6
- data/lib/friendly_id/base.rb +59 -60
- data/lib/friendly_id/candidates.rb +9 -11
- data/lib/friendly_id/configuration.rb +6 -7
- data/lib/friendly_id/finder_methods.rb +63 -15
- data/lib/friendly_id/finders.rb +66 -66
- data/lib/friendly_id/history.rb +62 -63
- data/lib/friendly_id/initializer.rb +4 -4
- data/lib/friendly_id/migration.rb +6 -6
- data/lib/friendly_id/object_utils.rb +2 -2
- data/lib/friendly_id/reserved.rb +30 -32
- data/lib/friendly_id/scoped.rb +99 -102
- data/lib/friendly_id/sequentially_slugged/calculator.rb +69 -0
- data/lib/friendly_id/sequentially_slugged.rb +17 -64
- data/lib/friendly_id/simple_i18n.rb +78 -69
- data/lib/friendly_id/slug.rb +1 -2
- data/lib/friendly_id/slug_generator.rb +1 -3
- data/lib/friendly_id/slugged.rb +237 -238
- data/lib/friendly_id/version.rb +1 -1
- data/lib/friendly_id.rb +47 -49
- data/lib/generators/friendly_id_generator.rb +9 -9
- data/test/base_test.rb +10 -13
- data/test/benchmarks/finders.rb +28 -26
- data/test/benchmarks/object_utils.rb +13 -13
- data/test/candidates_test.rb +17 -18
- data/test/configuration_test.rb +7 -11
- data/test/core_test.rb +1 -2
- data/test/databases.yml +4 -3
- data/test/finders_test.rb +36 -13
- data/test/generator_test.rb +16 -26
- data/test/helper.rb +31 -24
- data/test/history_test.rb +70 -74
- data/test/numeric_slug_test.rb +4 -4
- data/test/object_utils_test.rb +0 -2
- data/test/reserved_test.rb +9 -11
- data/test/schema.rb +5 -4
- data/test/scoped_test.rb +18 -20
- data/test/sequentially_slugged_test.rb +65 -50
- data/test/shared.rb +15 -16
- data/test/simple_i18n_test.rb +22 -12
- data/test/slugged_test.rb +125 -113
- data/test/sti_test.rb +19 -21
- data.tar.gz.sig +0 -0
- metadata +37 -32
- metadata.gz.sig +0 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gemspec path: "../"
|
4
|
+
|
5
|
+
gem "activerecord", "~> 6.1.4"
|
6
|
+
gem "railties", "~> 6.1.4"
|
7
|
+
|
8
|
+
# Database Configuration
|
9
|
+
group :development, :test do
|
10
|
+
platforms :jruby do
|
11
|
+
gem "activerecord-jdbcmysql-adapter", "~> 61.0"
|
12
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 61.0"
|
13
|
+
gem "kramdown"
|
14
|
+
end
|
15
|
+
|
16
|
+
platforms :ruby, :rbx do
|
17
|
+
gem "sqlite3"
|
18
|
+
gem "mysql2"
|
19
|
+
gem "pg"
|
20
|
+
gem "redcarpet"
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gemspec path: "../"
|
4
|
+
|
5
|
+
gem "activerecord", "~> 7.0.0"
|
6
|
+
gem "railties", "~> 7.0.0"
|
7
|
+
|
8
|
+
# Database Configuration
|
9
|
+
group :development, :test do
|
10
|
+
platforms :jruby do
|
11
|
+
gem "activerecord-jdbcmysql-adapter", "~> 61.0"
|
12
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 61.0"
|
13
|
+
gem "kramdown"
|
14
|
+
end
|
15
|
+
|
16
|
+
platforms :ruby, :rbx do
|
17
|
+
gem "sqlite3"
|
18
|
+
gem "mysql2"
|
19
|
+
gem "pg"
|
20
|
+
gem "redcarpet"
|
21
|
+
end
|
22
|
+
end
|
data/guide.rb
CHANGED
@@ -3,14 +3,21 @@
|
|
3
3
|
# This script generates the Guide.md file included in the Yard docs.
|
4
4
|
|
5
5
|
def comments_from path
|
6
|
-
path
|
7
|
-
|
8
|
-
|
6
|
+
path = File.expand_path("../lib/friendly_id/#{path}", __FILE__)
|
7
|
+
matches = File.read(path).match(/\n\s*# @guide begin\n(.*)\s*# @guide end/m)
|
8
|
+
|
9
|
+
return if matches.nil?
|
10
|
+
|
11
|
+
match = matches[1].to_s
|
12
|
+
match.split("\n")
|
13
|
+
.map { |x| x.sub(/^\s*#\s?/, "") } # Strip off the comment, leading whitespace, and the space after the comment
|
14
|
+
.reject { |x| x =~ /^@/ } # Ignore yarddoc tags for the guide
|
15
|
+
.join("\n").strip
|
9
16
|
end
|
10
17
|
|
11
|
-
File.open(File.expand_path(
|
12
|
-
[
|
13
|
-
|
18
|
+
File.open(File.expand_path("../Guide.md", __FILE__), "w:utf-8") do |guide|
|
19
|
+
["../friendly_id.rb", "base.rb", "finders.rb", "slugged.rb", "history.rb",
|
20
|
+
"scoped.rb", "simple_i18n.rb", "reserved.rb"].each do |file|
|
14
21
|
guide.write comments_from file
|
15
22
|
guide.write "\n"
|
16
23
|
end
|
data/lib/friendly_id/base.rb
CHANGED
@@ -1,62 +1,61 @@
|
|
1
1
|
module FriendlyId
|
2
|
-
|
3
|
-
|
4
|
-
## Setting Up FriendlyId in Your Model
|
5
|
-
|
6
|
-
To use FriendlyId in your ActiveRecord models, you must first either extend or
|
7
|
-
include the FriendlyId module (it makes no difference), then invoke the
|
8
|
-
{FriendlyId::Base#friendly_id friendly_id} method to configure your desired
|
9
|
-
options:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
The most important option is `:use`, which you use to tell FriendlyId which
|
17
|
-
addons it should use. See the documentation for {FriendlyId::Base#friendly_id} for a list of all
|
18
|
-
available addons, or skim through the rest of the docs to get a high-level
|
19
|
-
overview.
|
20
|
-
|
21
|
-
*A note about single table inheritance (STI): you must extend FriendlyId in
|
22
|
-
all classes that participate in STI, both your parent classes and their
|
23
|
-
children.*
|
24
|
-
|
25
|
-
### The Default Setup: Simple Models
|
26
|
-
|
27
|
-
The simplest way to use FriendlyId is with a model that has a uniquely indexed
|
28
|
-
column with no spaces or special characters, and that is seldom or never
|
29
|
-
updated. The most common example of this is a user name:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
In this case, FriendlyId assumes you want to use the column as-is; it will never
|
42
|
-
modify the value of the column, and your application should ensure that the
|
43
|
-
value is unique and admissible in a URL:
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
Writing the code to process an arbitrary string into a good identifier for use
|
54
|
-
in a URL can be repetitive and surprisingly tricky, so for this reason it's
|
55
|
-
often better and easier to use {FriendlyId::Slugged slugs}.
|
56
|
-
|
57
|
-
|
2
|
+
# @guide begin
|
3
|
+
#
|
4
|
+
# ## Setting Up FriendlyId in Your Model
|
5
|
+
#
|
6
|
+
# To use FriendlyId in your ActiveRecord models, you must first either extend or
|
7
|
+
# include the FriendlyId module (it makes no difference), then invoke the
|
8
|
+
# {FriendlyId::Base#friendly_id friendly_id} method to configure your desired
|
9
|
+
# options:
|
10
|
+
#
|
11
|
+
# class Foo < ActiveRecord::Base
|
12
|
+
# include FriendlyId
|
13
|
+
# friendly_id :bar, :use => [:slugged, :simple_i18n]
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# The most important option is `:use`, which you use to tell FriendlyId which
|
17
|
+
# addons it should use. See the documentation for {FriendlyId::Base#friendly_id} for a list of all
|
18
|
+
# available addons, or skim through the rest of the docs to get a high-level
|
19
|
+
# overview.
|
20
|
+
#
|
21
|
+
# *A note about single table inheritance (STI): you must extend FriendlyId in
|
22
|
+
# all classes that participate in STI, both your parent classes and their
|
23
|
+
# children.*
|
24
|
+
#
|
25
|
+
# ### The Default Setup: Simple Models
|
26
|
+
#
|
27
|
+
# The simplest way to use FriendlyId is with a model that has a uniquely indexed
|
28
|
+
# column with no spaces or special characters, and that is seldom or never
|
29
|
+
# updated. The most common example of this is a user name:
|
30
|
+
#
|
31
|
+
# class User < ActiveRecord::Base
|
32
|
+
# extend FriendlyId
|
33
|
+
# friendly_id :login
|
34
|
+
# validates_format_of :login, :with => /\A[a-z0-9]+\z/i
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# @user = User.friendly.find "joe" # the old User.find(1) still works, too
|
38
|
+
# @user.to_param # returns "joe"
|
39
|
+
# redirect_to @user # the URL will be /users/joe
|
40
|
+
#
|
41
|
+
# In this case, FriendlyId assumes you want to use the column as-is; it will never
|
42
|
+
# modify the value of the column, and your application should ensure that the
|
43
|
+
# value is unique and admissible in a URL:
|
44
|
+
#
|
45
|
+
# class City < ActiveRecord::Base
|
46
|
+
# extend FriendlyId
|
47
|
+
# friendly_id :name
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# @city.friendly.find "Viña del Mar"
|
51
|
+
# redirect_to @city # the URL will be /cities/Viña%20del%20Mar
|
52
|
+
#
|
53
|
+
# Writing the code to process an arbitrary string into a good identifier for use
|
54
|
+
# in a URL can be repetitive and surprisingly tricky, so for this reason it's
|
55
|
+
# often better and easier to use {FriendlyId::Slugged slugs}.
|
56
|
+
#
|
57
|
+
# @guide end
|
58
58
|
module Base
|
59
|
-
|
60
59
|
# Configure FriendlyId's behavior in a model.
|
61
60
|
#
|
62
61
|
# class Post < ActiveRecord::Base
|
@@ -205,10 +204,10 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
205
204
|
#
|
206
205
|
# @yieldparam config The model class's {FriendlyId::Configuration friendly_id_config}.
|
207
206
|
def friendly_id(base = nil, options = {}, &block)
|
208
|
-
yield friendly_id_config if
|
207
|
+
yield friendly_id_config if block
|
209
208
|
friendly_id_config.dependent = options.delete :dependent
|
210
209
|
friendly_id_config.use options.delete :use
|
211
|
-
friendly_id_config.send :set, base ? options.merge(:
|
210
|
+
friendly_id_config.send :set, base ? options.merge(base: base) : options
|
212
211
|
include Model
|
213
212
|
end
|
214
213
|
|
@@ -270,7 +269,7 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
270
269
|
|
271
270
|
# Clears slug on duplicate records when calling `dup`.
|
272
271
|
def dup
|
273
|
-
super.tap { |duplicate| duplicate.slug = nil if duplicate.respond_to?(
|
272
|
+
super.tap { |duplicate| duplicate.slug = nil if duplicate.respond_to?("slug=") }
|
274
273
|
end
|
275
274
|
end
|
276
275
|
end
|
@@ -1,11 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require "securerandom"
|
2
2
|
|
3
3
|
module FriendlyId
|
4
|
-
|
5
4
|
# This class provides the slug candidate functionality.
|
6
5
|
# @see FriendlyId::Slugged
|
7
6
|
class Candidates
|
8
|
-
|
9
7
|
include Enumerable
|
10
8
|
|
11
9
|
def initialize(object, *array)
|
@@ -14,8 +12,8 @@ module FriendlyId
|
|
14
12
|
end
|
15
13
|
|
16
14
|
def each(*args, &block)
|
17
|
-
return candidates unless
|
18
|
-
candidates.each{ |candidate| yield candidate }
|
15
|
+
return candidates unless block
|
16
|
+
candidates.each { |candidate| yield candidate }
|
19
17
|
end
|
20
18
|
|
21
19
|
private
|
@@ -29,13 +27,13 @@ module FriendlyId
|
|
29
27
|
|
30
28
|
def normalize(candidates)
|
31
29
|
candidates.map do |candidate|
|
32
|
-
@object.normalize_friendly_id(candidate.map(&:call).join(
|
33
|
-
end.select {|x| wanted?(x)}
|
30
|
+
@object.normalize_friendly_id(candidate.map(&:call).join(" "))
|
31
|
+
end.select { |x| wanted?(x) }
|
34
32
|
end
|
35
33
|
|
36
34
|
def filter(candidates)
|
37
|
-
unless candidates.all? {|x| reserved?(x)}
|
38
|
-
candidates.reject! {|x| reserved?(x)}
|
35
|
+
unless candidates.all? { |x| reserved?(x) }
|
36
|
+
candidates.reject! { |x| reserved?(x) }
|
39
37
|
end
|
40
38
|
candidates
|
41
39
|
end
|
@@ -44,7 +42,7 @@ module FriendlyId
|
|
44
42
|
array.map do |candidate|
|
45
43
|
case candidate
|
46
44
|
when String
|
47
|
-
[->{candidate}]
|
45
|
+
[-> { candidate }]
|
48
46
|
when Array
|
49
47
|
to_candidate_array(object, candidate).flatten
|
50
48
|
when Symbol
|
@@ -53,7 +51,7 @@ module FriendlyId
|
|
53
51
|
if candidate.respond_to?(:call)
|
54
52
|
[candidate]
|
55
53
|
else
|
56
|
-
[->{candidate.to_s}]
|
54
|
+
[-> { candidate.to_s }]
|
57
55
|
end
|
58
56
|
end
|
59
57
|
end
|
@@ -2,7 +2,6 @@ module FriendlyId
|
|
2
2
|
# The configuration parameters passed to {Base#friendly_id} will be stored in
|
3
3
|
# this object.
|
4
4
|
class Configuration
|
5
|
-
|
6
5
|
attr_writer :base
|
7
6
|
|
8
7
|
# The default configuration options.
|
@@ -25,10 +24,10 @@ module FriendlyId
|
|
25
24
|
attr_accessor :routes
|
26
25
|
|
27
26
|
def initialize(model_class, values = nil)
|
28
|
-
@base
|
29
|
-
@model_class
|
30
|
-
@defaults
|
31
|
-
@modules
|
27
|
+
@base = nil
|
28
|
+
@model_class = model_class
|
29
|
+
@defaults = {}
|
30
|
+
@modules = []
|
32
31
|
@finder_methods = FriendlyId::FinderMethods
|
33
32
|
self.routes = :friendly
|
34
33
|
set values
|
@@ -102,11 +101,11 @@ module FriendlyId
|
|
102
101
|
private
|
103
102
|
|
104
103
|
def get_module(object)
|
105
|
-
Module === object ? object : FriendlyId.const_get(object.to_s.titleize.camelize.gsub(/\s+/,
|
104
|
+
Module === object ? object : FriendlyId.const_get(object.to_s.titleize.camelize.gsub(/\s+/, ""))
|
106
105
|
end
|
107
106
|
|
108
107
|
def set(values)
|
109
|
-
values
|
108
|
+
values&.each { |name, value| send "#{name}=", value }
|
110
109
|
end
|
111
110
|
end
|
112
111
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
module FriendlyId
|
2
|
-
|
3
2
|
module FinderMethods
|
4
|
-
|
5
3
|
# Finds a record using the given id.
|
6
4
|
#
|
7
5
|
# If the id is "unfriendly", it will call the original find method.
|
@@ -9,19 +7,33 @@ module FriendlyId
|
|
9
7
|
# id matching '123' and then fall back to looking for a record with the
|
10
8
|
# numeric id '123'.
|
11
9
|
#
|
10
|
+
# @param [Boolean] allow_nil (default: false)
|
11
|
+
# Use allow_nil: true if you'd like the finder to return nil instead of
|
12
|
+
# raising ActivRecord::RecordNotFound
|
13
|
+
#
|
14
|
+
# ### Example
|
15
|
+
#
|
16
|
+
# MyModel.friendly.find("bad-slug")
|
17
|
+
# #=> raise ActiveRecord::RecordNotFound
|
18
|
+
#
|
19
|
+
# MyModel.friendly.find("bad-slug", allow_nil: true)
|
20
|
+
# #=> nil
|
21
|
+
#
|
12
22
|
# Since FriendlyId 5.0, if the id is a nonnumeric string like '123-foo' it
|
13
23
|
# will *only* search by friendly id and not fall back to the regular find
|
14
24
|
# method.
|
15
25
|
#
|
16
26
|
# If you want to search only by the friendly id, use {#find_by_friendly_id}.
|
17
27
|
# @raise ActiveRecord::RecordNotFound
|
18
|
-
def find(*args)
|
28
|
+
def find(*args, allow_nil: false)
|
19
29
|
id = args.first
|
20
|
-
return super if args.count != 1 || id.unfriendly_id?
|
21
|
-
first_by_friendly_id(id).tap {|result| return result unless result.nil?}
|
22
|
-
return super if potential_primary_key?(id)
|
23
|
-
|
24
|
-
|
30
|
+
return super(*args) if args.count != 1 || id.unfriendly_id?
|
31
|
+
first_by_friendly_id(id).tap { |result| return result unless result.nil? }
|
32
|
+
return super(*args) if potential_primary_key?(id)
|
33
|
+
|
34
|
+
raise_not_found_exception(id) unless allow_nil
|
35
|
+
rescue ActiveRecord::RecordNotFound => exception
|
36
|
+
raise exception unless allow_nil
|
25
37
|
end
|
26
38
|
|
27
39
|
# Returns true if a record with the given id exists.
|
@@ -35,11 +47,11 @@ module FriendlyId
|
|
35
47
|
# `find`.
|
36
48
|
# @raise ActiveRecord::RecordNotFound
|
37
49
|
def find_by_friendly_id(id)
|
38
|
-
first_by_friendly_id(id) or
|
50
|
+
first_by_friendly_id(id) or raise_not_found_exception(id)
|
39
51
|
end
|
40
52
|
|
41
53
|
def exists_by_friendly_id?(id)
|
42
|
-
where(friendly_id_config.query_field => id).exists?
|
54
|
+
where(friendly_id_config.query_field => parse_friendly_id(id)).exists?
|
43
55
|
end
|
44
56
|
|
45
57
|
private
|
@@ -50,7 +62,11 @@ module FriendlyId
|
|
50
62
|
key_type = key_type.type if key_type.respond_to?(:type)
|
51
63
|
case key_type
|
52
64
|
when :integer
|
53
|
-
|
65
|
+
begin
|
66
|
+
Integer(id, 10)
|
67
|
+
rescue
|
68
|
+
false
|
69
|
+
end
|
54
70
|
when :uuid
|
55
71
|
id.match(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
|
56
72
|
else
|
@@ -59,17 +75,49 @@ module FriendlyId
|
|
59
75
|
end
|
60
76
|
|
61
77
|
def first_by_friendly_id(id)
|
62
|
-
find_by(friendly_id_config.query_field => id
|
78
|
+
find_by(friendly_id_config.query_field => parse_friendly_id(id))
|
79
|
+
end
|
80
|
+
|
81
|
+
# Parse the given value to make it suitable for use as a slug according to
|
82
|
+
# your application's rules.
|
83
|
+
#
|
84
|
+
# This method is not intended to be invoked directly; FriendlyId uses it
|
85
|
+
# internally to process a slug into string to use as a finder.
|
86
|
+
#
|
87
|
+
# However, if FriendlyId's default slug parsing doesn't suit your needs,
|
88
|
+
# you can override this method in your model class to control exactly how
|
89
|
+
# slugs are generated.
|
90
|
+
#
|
91
|
+
# ### Example
|
92
|
+
#
|
93
|
+
# class Person < ActiveRecord::Base
|
94
|
+
# extend FriendlyId
|
95
|
+
# friendly_id :name_and_location
|
96
|
+
#
|
97
|
+
# def name_and_location
|
98
|
+
# "#{name} from #{location}"
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# # Use default slug, but lower case
|
102
|
+
# # If `id` is "Jane-Doe" or "JANE-DOE", this finds data by "jane-doe"
|
103
|
+
# def parse_friendly_id(slug)
|
104
|
+
# super.downcase
|
105
|
+
# end
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# @param [#to_s] value The slug to be parsed.
|
109
|
+
# @return The parsed slug, which is not modified by default.
|
110
|
+
def parse_friendly_id(value)
|
111
|
+
value
|
63
112
|
end
|
64
113
|
|
65
114
|
def raise_not_found_exception(id)
|
66
115
|
message = "can't find record with friendly id: #{id.inspect}"
|
67
|
-
if ActiveRecord.version < Gem::Version.create(
|
116
|
+
if ActiveRecord.version < Gem::Version.create("5.0")
|
68
117
|
raise ActiveRecord::RecordNotFound.new(message)
|
69
|
-
else
|
118
|
+
else
|
70
119
|
raise ActiveRecord::RecordNotFound.new(message, name, friendly_id_config.query_field, id)
|
71
120
|
end
|
72
121
|
end
|
73
|
-
|
74
122
|
end
|
75
123
|
end
|
data/lib/friendly_id/finders.rb
CHANGED
@@ -1,73 +1,73 @@
|
|
1
1
|
module FriendlyId
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
2
|
+
# @guide begin
|
3
|
+
#
|
4
|
+
# ## Performing Finds with FriendlyId
|
5
|
+
#
|
6
|
+
# FriendlyId offers enhanced finders which will search for your record by
|
7
|
+
# friendly id, and fall back to the numeric id if necessary. This makes it easy
|
8
|
+
# to add FriendlyId to an existing application with minimal code modification.
|
9
|
+
#
|
10
|
+
# By default, these methods are available only on the `friendly` scope:
|
11
|
+
#
|
12
|
+
# Restaurant.friendly.find('plaza-diner') #=> works
|
13
|
+
# Restaurant.friendly.find(23) #=> also works
|
14
|
+
# Restaurant.find(23) #=> still works
|
15
|
+
# Restaurant.find('plaza-diner') #=> will not work
|
16
|
+
#
|
17
|
+
# ### Restoring FriendlyId 4.0-style finders
|
18
|
+
#
|
19
|
+
# Prior to version 5.0, FriendlyId overrode the default finder methods to perform
|
20
|
+
# friendly finds all the time. This required modifying parts of Rails that did
|
21
|
+
# not have a public API, which was harder to maintain and at times caused
|
22
|
+
# compatiblity problems. In 5.0 we decided to change the library's defaults and add
|
23
|
+
# the friendly finder methods only to the `friendly` scope in order to boost
|
24
|
+
# compatiblity. However, you can still opt-in to original functionality very
|
25
|
+
# easily by using the `:finders` addon:
|
26
|
+
#
|
27
|
+
# class Restaurant < ActiveRecord::Base
|
28
|
+
# extend FriendlyId
|
29
|
+
#
|
30
|
+
# scope :active, -> {where(:active => true)}
|
31
|
+
#
|
32
|
+
# friendly_id :name, :use => [:slugged, :finders]
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Restaurant.friendly.find('plaza-diner') #=> works
|
36
|
+
# Restaurant.find('plaza-diner') #=> now also works
|
37
|
+
# Restaurant.active.find('plaza-diner') #=> now also works
|
38
|
+
#
|
39
|
+
# ### Updating your application to use FriendlyId's finders
|
40
|
+
#
|
41
|
+
# Unless you've chosen to use the `:finders` addon, be sure to modify the finders
|
42
|
+
# in your controllers to use the `friendly` scope. For example:
|
43
|
+
#
|
44
|
+
# # before
|
45
|
+
# def set_restaurant
|
46
|
+
# @restaurant = Restaurant.find(params[:id])
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# # after
|
50
|
+
# def set_restaurant
|
51
|
+
# @restaurant = Restaurant.friendly.find(params[:id])
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# #### Active Admin
|
55
|
+
#
|
56
|
+
# Unless you use the `:finders` addon, you should modify your admin controllers
|
57
|
+
# for models that use FriendlyId with something similar to the following:
|
58
|
+
#
|
59
|
+
# controller do
|
60
|
+
# def find_resource
|
61
|
+
# scoped_collection.friendly.find(params[:id])
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# @guide end
|
65
66
|
module Finders
|
66
|
-
|
67
67
|
module ClassMethods
|
68
68
|
if (ActiveRecord::VERSION::MAJOR == 4) && (ActiveRecord::VERSION::MINOR == 0)
|
69
69
|
def relation_delegate_class(klass)
|
70
|
-
relation_class_name = :"#{klass.to_s.gsub(
|
70
|
+
relation_class_name = :"#{klass.to_s.gsub("::", "_")}_#{to_s.gsub("::", "_")}"
|
71
71
|
klass.const_get(relation_class_name)
|
72
72
|
end
|
73
73
|
end
|
@@ -82,7 +82,7 @@ for models that use FriendlyId with something similar to the following:
|
|
82
82
|
end
|
83
83
|
|
84
84
|
# Support for friendly finds on associations for Rails 4.0.1 and above.
|
85
|
-
if ::ActiveRecord.const_defined?(
|
85
|
+
if ::ActiveRecord.const_defined?("AssociationRelation")
|
86
86
|
model_class.extend(ClassMethods)
|
87
87
|
association_relation_delegate_class = model_class.relation_delegate_class(::ActiveRecord::AssociationRelation)
|
88
88
|
association_relation_delegate_class.send(:include, model_class.friendly_id_config.finder_methods)
|