friendly_id 4.1.0.beta.1 → 5.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +7 -12
- data/Changelog.md +4 -0
- data/Gemfile +2 -2
- data/Guide.rdoc +34 -63
- data/README.md +116 -60
- data/Rakefile +5 -1
- data/WhatsNew.md +2 -94
- data/friendly_id.gemspec +10 -20
- data/gemfiles/Gemfile.rails-4.0.rb +19 -0
- data/lib/friendly_id.rb +11 -6
- data/lib/friendly_id/.gitattributes +1 -0
- data/lib/friendly_id/base.rb +6 -65
- data/lib/friendly_id/candidates.rb +41 -0
- data/lib/friendly_id/configuration.rb +10 -6
- data/lib/friendly_id/history.rb +22 -60
- data/lib/friendly_id/object_utils.rb +1 -1
- data/lib/friendly_id/scoped.rb +40 -34
- data/lib/friendly_id/scopes.rb +28 -0
- data/lib/friendly_id/simple_i18n.rb +13 -3
- data/lib/friendly_id/slug.rb +0 -1
- data/lib/friendly_id/slug_generator.rb +9 -68
- data/lib/friendly_id/slugged.rb +22 -34
- data/lib/friendly_id/version.rb +3 -0
- data/lib/generators/friendly_id_generator.rb +5 -4
- data/test/helper.rb +1 -1
- data/test/history_test.rb +63 -56
- data/test/object_utils_test.rb +0 -1
- data/test/schema.rb +1 -10
- data/test/shared.rb +27 -23
- data/test/simple_i18n_test.rb +3 -2
- data/test/slugged_test.rb +17 -48
- data/test/sti_test.rb +2 -2
- metadata +40 -103
- data/gemfiles/Gemfile.rails-3.0.rb +0 -21
- data/gemfiles/Gemfile.rails-3.1.rb +0 -22
- data/gemfiles/Gemfile.rails-3.2.rb +0 -22
- data/lib/friendly_id/finder_methods.rb +0 -35
- data/lib/friendly_id/globalize.rb +0 -115
- data/test/globalize_test.rb +0 -57
data/WhatsNew.md
CHANGED
@@ -1,95 +1,3 @@
|
|
1
|
-
# What's New in FriendlyId
|
1
|
+
# What's New in FriendlyId 5?
|
2
2
|
|
3
|
-
##
|
4
|
-
|
5
|
-
FriendlyId is mostly a different codebase from FriendlyId 3. However, this isn't
|
6
|
-
the "big rewrite," it's the "small rewrite:"
|
7
|
-
|
8
|
-
Adding new features with each release is not sustainable. This release *removes*
|
9
|
-
features, but makes it possible to add them back as addons. We can also remove
|
10
|
-
some complexity by relying on the better default functionality provided by newer
|
11
|
-
versions of Active Support and Active Record.
|
12
|
-
|
13
|
-
Here's what's changed:
|
14
|
-
|
15
|
-
## New configuration and setup
|
16
|
-
|
17
|
-
FriendlyId is no longer added to Active Record by default, you must explicitly
|
18
|
-
add it to each model you want to use it in. The method and options have also
|
19
|
-
changed:
|
20
|
-
|
21
|
-
# FriendlyId 3
|
22
|
-
class Post < ActiveRecord::Base
|
23
|
-
has_friendly_id :title, :use_slugs => true
|
24
|
-
end
|
25
|
-
|
26
|
-
# FriendlyId 4
|
27
|
-
class Post < ActiveRecord::Base
|
28
|
-
extend FriendlyId
|
29
|
-
friendly_id :title, :use => :slugged
|
30
|
-
end
|
31
|
-
|
32
|
-
It also adds a new "defaults" method for configuring all models:
|
33
|
-
|
34
|
-
FriendlyId.defaults do |config|
|
35
|
-
config.use :slugged, :reserved
|
36
|
-
config.base = :name
|
37
|
-
end
|
38
|
-
|
39
|
-
## Active Record 3+ only
|
40
|
-
|
41
|
-
For 2.3 support, you can use FriendlyId 3.x, which will continue to be
|
42
|
-
maintained until people don't want it any more.
|
43
|
-
|
44
|
-
## In-table slugs
|
45
|
-
|
46
|
-
FriendlyId no longer creates a separate slugs table - it just stores the
|
47
|
-
generated slug value in the model table, which is simpler, faster and what most
|
48
|
-
want by default. Keeping slug history in a separate table is an
|
49
|
-
{FriendlyId::History optional add-on} for FriendlyId 4.
|
50
|
-
|
51
|
-
## No more multiple finds
|
52
|
-
|
53
|
-
Person.find "joe-schmoe" # Supported
|
54
|
-
Person.find ["joe-schmoe", "john-doe"] # No longer supported
|
55
|
-
|
56
|
-
If you want find by more than one friendly id, build your own query:
|
57
|
-
|
58
|
-
Person.where(:slug => ["joe-schmoe", "john-doe"])
|
59
|
-
|
60
|
-
This lets us do *far* less monkeypatching in Active Record. How much less?
|
61
|
-
FriendlyId overrides the base find with a mere 2 lines of code, and otherwise
|
62
|
-
changes nothing else. This means more stability and less breakage between Rails
|
63
|
-
updates.
|
64
|
-
|
65
|
-
## No more finder status
|
66
|
-
|
67
|
-
FriendlyId 3 offered finder statuses to help you determine when an outdated
|
68
|
-
or non-friendly id was used to find the record, so that you could decide whether
|
69
|
-
to permanently redirect to the canonical URL. However, there's a simpler way to
|
70
|
-
do that, so this feature has been removed:
|
71
|
-
|
72
|
-
if request.path != person_path(@person)
|
73
|
-
return redirect_to @person, :status => :moved_permanently
|
74
|
-
end
|
75
|
-
|
76
|
-
## Bye-bye Babosa
|
77
|
-
|
78
|
-
[Babosa](http://github.com/norman/babosa) is FriendlyId 3's slugging library.
|
79
|
-
|
80
|
-
FriendlyId 4 doesn't use it by default because the most important pieces of it
|
81
|
-
were already accepted into Active Support 3.
|
82
|
-
|
83
|
-
However, Babosa is still useful, for example, for idiomatically transliterating
|
84
|
-
Cyrillic ([or other
|
85
|
-
language](https://github.com/norman/babosa/tree/master/lib/babosa/transliterator))
|
86
|
-
strings to ASCII. It's very easy to include - just override
|
87
|
-
`#normalize_friendly_id` in your model:
|
88
|
-
|
89
|
-
class MyModel < ActiveRecord::Base
|
90
|
-
...
|
91
|
-
|
92
|
-
def normalize_friendly_id(text)
|
93
|
-
text.to_slug.normalize! :transliterations => :russian
|
94
|
-
end
|
95
|
-
end
|
3
|
+
## Write me
|
data/friendly_id.gemspec
CHANGED
@@ -1,43 +1,33 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
|
-
|
4
|
-
require "friendly_id"
|
2
|
+
require File.expand_path("../lib/friendly_id/version", __FILE__)
|
5
3
|
|
6
4
|
Gem::Specification.new do |s|
|
7
5
|
s.name = "friendly_id"
|
8
6
|
s.version = FriendlyId::VERSION
|
9
7
|
s.authors = ["Norman Clarke", "Philip Arndt"]
|
10
|
-
s.email = ["norman@njclarke.com", "
|
11
|
-
s.homepage = "http://github.com/
|
8
|
+
s.email = ["norman@njclarke.com", "p@arndt.io"]
|
9
|
+
s.homepage = "http://github.com/FriendlyId/friendly_id"
|
12
10
|
s.summary = "A comprehensive slugging and pretty-URL plugin."
|
13
11
|
s.rubyforge_project = "friendly_id"
|
14
12
|
s.files = `git ls-files`.split("\n")
|
15
13
|
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
16
14
|
s.require_paths = ["lib"]
|
15
|
+
s.license = 'MIT'
|
16
|
+
|
17
|
+
s.required_ruby_version = '>= 1.9.3'
|
17
18
|
|
18
|
-
s.add_development_dependency "railties", "~>
|
19
|
-
s.add_development_dependency "activerecord", "~>
|
20
|
-
s.add_development_dependency "minitest", "
|
21
|
-
s.add_development_dependency "mocha"
|
22
|
-
s.add_development_dependency "maruku"
|
19
|
+
s.add_development_dependency "railties", "~> 4.0.0"
|
20
|
+
s.add_development_dependency "activerecord", "~> 4.0.0"
|
21
|
+
s.add_development_dependency "minitest", ">= 4.4.0"
|
22
|
+
s.add_development_dependency "mocha", "~> 0.13.3"
|
23
23
|
s.add_development_dependency "yard"
|
24
24
|
s.add_development_dependency "i18n"
|
25
25
|
s.add_development_dependency "ffaker"
|
26
26
|
s.add_development_dependency "simplecov"
|
27
|
-
s.add_development_dependency "globalize3"
|
28
27
|
|
29
28
|
s.description = <<-EOM
|
30
29
|
FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for
|
31
30
|
Ruby on Rails. It allows you to create pretty URLs and work with human-friendly
|
32
31
|
strings as if they were numeric ids for Active Record models.
|
33
32
|
EOM
|
34
|
-
|
35
|
-
s.post_install_message = <<-EOM
|
36
|
-
NOTE: FriendlyId 4.x breaks compatibility with 3.x. If you're upgrading
|
37
|
-
from 3.x, please see this document:
|
38
|
-
|
39
|
-
http://rubydoc.info/github/norman/friendly_id/master/file/WhatsNew.md
|
40
|
-
|
41
|
-
EOM
|
42
|
-
|
43
33
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec path: '../'
|
4
|
+
|
5
|
+
# Database Configuration
|
6
|
+
group :development, :test do
|
7
|
+
platforms :jruby do
|
8
|
+
gem 'activerecord-jdbcsqlite3-adapter', '>= 1.3.0.beta2'
|
9
|
+
gem 'activerecord-jdbcmysql-adapter', '>= 1.3.0.beta2'
|
10
|
+
gem 'activerecord-jdbcpostgresql-adapter', '>= 1.3.0.beta2'
|
11
|
+
gem 'jruby-openssl'
|
12
|
+
end
|
13
|
+
|
14
|
+
platforms :ruby do
|
15
|
+
gem 'sqlite3'
|
16
|
+
gem 'mysql2'
|
17
|
+
gem 'pg'
|
18
|
+
end
|
19
|
+
end
|
data/lib/friendly_id.rb
CHANGED
@@ -3,7 +3,7 @@ require "thread"
|
|
3
3
|
require "friendly_id/base"
|
4
4
|
require "friendly_id/object_utils"
|
5
5
|
require "friendly_id/configuration"
|
6
|
-
require "friendly_id/
|
6
|
+
require "friendly_id/scopes"
|
7
7
|
|
8
8
|
=begin
|
9
9
|
|
@@ -44,9 +44,6 @@ with numeric ids:
|
|
44
44
|
=end
|
45
45
|
module FriendlyId
|
46
46
|
|
47
|
-
# The current version.
|
48
|
-
VERSION = "4.1.0.beta.1"
|
49
|
-
|
50
47
|
@mutex = Mutex.new
|
51
48
|
|
52
49
|
autoload :History, "friendly_id/history"
|
@@ -55,7 +52,6 @@ module FriendlyId
|
|
55
52
|
autoload :Reserved, "friendly_id/reserved"
|
56
53
|
autoload :Scoped, "friendly_id/scoped"
|
57
54
|
autoload :Slugged, "friendly_id/slugged"
|
58
|
-
autoload :Globalize, "friendly_id/globalize"
|
59
55
|
|
60
56
|
# FriendlyId takes advantage of `extended` to do basic model setup, primarily
|
61
57
|
# extending {FriendlyId::Base} to add {FriendlyId::Base#friendly_id
|
@@ -84,10 +80,11 @@ module FriendlyId
|
|
84
80
|
class << model_class
|
85
81
|
alias relation_without_friendly_id relation
|
86
82
|
end
|
87
|
-
model_class.
|
83
|
+
model_class.class_eval do
|
88
84
|
extend Base
|
89
85
|
@friendly_id_config = Class.new(Configuration).new(self)
|
90
86
|
FriendlyId.defaults.call @friendly_id_config
|
87
|
+
include Model
|
91
88
|
end
|
92
89
|
end
|
93
90
|
|
@@ -111,4 +108,12 @@ module FriendlyId
|
|
111
108
|
@defaults ||= lambda {|config| config.use :reserved}
|
112
109
|
end
|
113
110
|
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
|
114
119
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
version.rb merge=ours
|
data/lib/friendly_id/base.rb
CHANGED
@@ -156,8 +156,7 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
156
156
|
# @option options [Symbol,Module] :use The addon or name of an addon to use.
|
157
157
|
# By default, FriendlyId provides {FriendlyId::Slugged :slugged},
|
158
158
|
# {FriendlyId::History :history}, {FriendlyId::Reserved :reserved}, and
|
159
|
-
# {FriendlyId::Scoped :scoped}, {FriendlyId::SimpleI18n :simple_i18n}
|
160
|
-
# and {FriendlyId::Globalize :globalize}.
|
159
|
+
# {FriendlyId::Scoped :scoped}, and {FriendlyId::SimpleI18n :simple_i18n}.
|
161
160
|
#
|
162
161
|
# @option options [Array] :reserved_words Available when using +:reserved+,
|
163
162
|
# which is loaded by default. Sets an array of words banned for use as
|
@@ -169,7 +168,7 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
169
168
|
#
|
170
169
|
# @option options [Symbol] :sequence_separator Available when using +:slugged+.
|
171
170
|
# Configures the sequence of characters used to separate a slug from a
|
172
|
-
# sequence. Defaults to
|
171
|
+
# sequence. Defaults to +-+.
|
173
172
|
#
|
174
173
|
# @option options [Symbol] :slug_column Available when using +:slugged+.
|
175
174
|
# Configures the name of the column where FriendlyId will store the slug.
|
@@ -189,8 +188,8 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
189
188
|
yield friendly_id_config if block_given?
|
190
189
|
friendly_id_config.use options.delete :use
|
191
190
|
friendly_id_config.send :set, base ? options.merge(:base => base) : options
|
192
|
-
before_save {|rec| rec.instance_eval {@current_friendly_id = friendly_id}}
|
193
191
|
include Model
|
192
|
+
extend Scopes
|
194
193
|
end
|
195
194
|
|
196
195
|
# Returns the model class's {FriendlyId::Configuration friendly_id_config}.
|
@@ -201,73 +200,15 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
201
200
|
def friendly_id_config
|
202
201
|
@friendly_id_config ||= base_class.friendly_id_config.dup.tap do |config|
|
203
202
|
config.model_class = self
|
204
|
-
@relation_class = base_class.send(:relation_class)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
private
|
209
|
-
|
210
|
-
# Gets an instance of an the relation class.
|
211
|
-
#
|
212
|
-
# With FriendlyId this will be a subclass of ActiveRecord::Relation, rather than
|
213
|
-
# Relation itself, in order to avoid tainting all Active Record models with
|
214
|
-
# FriendlyId.
|
215
|
-
#
|
216
|
-
# Note that this method is essentially copied and pasted from Rails 3.2.9.rc1,
|
217
|
-
# with the exception of changing the relation class. Obviously this is less than
|
218
|
-
# ideal, but I know of no better way to accomplish this.
|
219
|
-
# @see #relation_class
|
220
|
-
def relation #:nodoc:
|
221
|
-
relation = relation_class.new(self, arel_table)
|
222
|
-
|
223
|
-
if finder_needs_type_condition?
|
224
|
-
relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
|
225
|
-
else
|
226
|
-
relation
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
# Gets (and if necessary, creates) a subclass of the model's relation class.
|
231
|
-
#
|
232
|
-
# Rather than including FriendlyId's overridden finder methods in
|
233
|
-
# ActiveRecord::Relation directly, FriendlyId adds them to a subclass
|
234
|
-
# specific to the AR model, and makes #relation return an instance of this
|
235
|
-
# class. By doing this, we ensure that only models that specifically extend
|
236
|
-
# FriendlyId have their finder methods overridden.
|
237
|
-
#
|
238
|
-
# Note that this method does not directly subclass ActiveRecord::Relation,
|
239
|
-
# but rather whatever class the @relation class instance variable is an
|
240
|
-
# instance of. In practice, this will almost always end up being
|
241
|
-
# ActiveRecord::Relation, but in case another plugin is using this same
|
242
|
-
# pattern to extend a model's finder functionality, FriendlyId will not
|
243
|
-
# replace it, but rather override it.
|
244
|
-
#
|
245
|
-
# This pattern can be seen as a poor man's "refinement"
|
246
|
-
# (http://timelessrepo.com/refinements-in-ruby), and while I **think** it
|
247
|
-
# will work quite well, I realize that it could cause unexpected issues,
|
248
|
-
# since the authors of Rails are probably not intending this kind of usage
|
249
|
-
# against a private API. If this ends up being problematic I will probably
|
250
|
-
# revert back to the old behavior of simply extending
|
251
|
-
# ActiveRecord::Relation.
|
252
|
-
def relation_class
|
253
|
-
@relation_class or begin
|
254
|
-
@relation_class = Class.new(relation_without_friendly_id.class) do
|
255
|
-
alias_method :find_one_without_friendly_id, :find_one
|
256
|
-
alias_method :exists_without_friendly_id?, :exists?
|
257
|
-
include FriendlyId::FinderMethods
|
258
|
-
end
|
259
|
-
# Set a name so that model instances can be marshalled. Use a
|
260
|
-
# ridiculously long name that will not conflict with anything.
|
261
|
-
# TODO: just use the constant, no need for the @relation_class variable.
|
262
|
-
const_set('FriendlyIdActiveRecordRelation', @relation_class)
|
263
203
|
end
|
264
204
|
end
|
265
205
|
end
|
266
206
|
|
267
207
|
# Instance methods that will be added to all classes using FriendlyId.
|
268
208
|
module Model
|
269
|
-
|
270
|
-
|
209
|
+
def self.included(model_class)
|
210
|
+
return if model_class.respond_to?(:friendly)
|
211
|
+
end
|
271
212
|
|
272
213
|
# Convenience method for accessing the class method of the same name.
|
273
214
|
def friendly_id_config
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module FriendlyId
|
4
|
+
|
5
|
+
class Candidates
|
6
|
+
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(object, *array)
|
10
|
+
@object = object
|
11
|
+
@candidates = to_candidate_array(object, array.flatten(1))
|
12
|
+
end
|
13
|
+
|
14
|
+
def each(*args, &block)
|
15
|
+
@candidates.each(*args) do |candidate|
|
16
|
+
yield @object.normalize_friendly_id(candidate.map(&:call).join(' '))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def to_candidate_array(object, array)
|
23
|
+
array.map do |candidate|
|
24
|
+
case candidate
|
25
|
+
when String
|
26
|
+
[->{candidate}]
|
27
|
+
when Array
|
28
|
+
to_candidate_array(object, candidate).flatten
|
29
|
+
when Symbol
|
30
|
+
[object.method(candidate)]
|
31
|
+
else
|
32
|
+
if candidate.respond_to?(:call)
|
33
|
+
[candidate]
|
34
|
+
else
|
35
|
+
[->{candidate.to_s}]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -58,18 +58,18 @@ module FriendlyId
|
|
58
58
|
# @param [#to_s,Module] *modules Arguments should be Modules, or symbols or
|
59
59
|
# strings that correspond with the name of a module inside the FriendlyId
|
60
60
|
# namespace. By default FriendlyId provides +:slugged+, +:history+,
|
61
|
-
# +:simple_i18n+,
|
61
|
+
# +:simple_i18n+, and +:scoped+.
|
62
62
|
def use(*modules)
|
63
63
|
modules.to_a.flatten.compact.map do |object|
|
64
|
-
mod =
|
65
|
-
model_class.
|
66
|
-
@
|
64
|
+
mod = get_module(object)
|
65
|
+
mod.setup(@model_class) if mod.respond_to?(:setup)
|
66
|
+
@model_class.send(:include, mod) unless uses? object
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
# Returns whether the given module is in use
|
71
|
-
def uses?(
|
72
|
-
@
|
71
|
+
def uses?(mod)
|
72
|
+
@model_class < get_module(mod)
|
73
73
|
end
|
74
74
|
|
75
75
|
# The column that FriendlyId will use to find the record when querying by
|
@@ -83,6 +83,10 @@ module FriendlyId
|
|
83
83
|
|
84
84
|
private
|
85
85
|
|
86
|
+
def get_module(object)
|
87
|
+
Module === object ? object : FriendlyId.const_get(object.to_s.classify)
|
88
|
+
end
|
89
|
+
|
86
90
|
def set(values)
|
87
91
|
values and values.each {|name, value| self.send "#{name}=", value}
|
88
92
|
end
|
data/lib/friendly_id/history.rb
CHANGED
@@ -58,13 +58,26 @@ method.
|
|
58
58
|
|
59
59
|
# Configures the model instance to use the History add-on.
|
60
60
|
def self.included(model_class)
|
61
|
-
model_class.
|
61
|
+
model_class.class_eval do
|
62
62
|
@friendly_id_config.use :slugged
|
63
|
-
|
64
|
-
|
63
|
+
|
64
|
+
has_many :slugs, -> {order("#{Slug.quoted_table_name}.id DESC")}, {
|
65
|
+
:as => :sluggable,
|
66
|
+
:dependent => :destroy,
|
67
|
+
:class_name => Slug.to_s
|
68
|
+
}
|
65
69
|
after_save :create_slug
|
66
|
-
|
67
|
-
|
70
|
+
def self.find_by_friendly_id(id)
|
71
|
+
includes(:slugs).where(slug_history_clause(id)).references(:slugs).first
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.exists_by_friendly_id?(id)
|
75
|
+
includes(:slugs).where(arel_table[friendly_id_config.query_field].eq(id).or(slug_history_clause(id))).exists?
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.slug_history_clause(id)
|
79
|
+
Slug.arel_table[:sluggable_type].eq(base_class.to_s).and(Slug.arel_table[:slug].eq(id))
|
80
|
+
end
|
68
81
|
end
|
69
82
|
end
|
70
83
|
|
@@ -75,65 +88,14 @@ method.
|
|
75
88
|
return if slugs.first.try(:slug) == friendly_id
|
76
89
|
# Allow reversion back to a previously used slug
|
77
90
|
relation = slugs.where(:slug => friendly_id)
|
78
|
-
|
79
|
-
|
91
|
+
if friendly_id_config.uses?(:scoped)
|
92
|
+
relation = relation.where(:scope => serialized_scope)
|
93
|
+
end
|
94
|
+
relation.delete_all
|
80
95
|
slugs.create! do |record|
|
81
96
|
record.slug = friendly_id
|
82
97
|
record.scope = serialized_scope if friendly_id_config.uses?(:scoped)
|
83
98
|
end
|
84
99
|
end
|
85
|
-
|
86
|
-
# Adds a finder that explictly uses slugs from the slug table.
|
87
|
-
module FinderMethods
|
88
|
-
|
89
|
-
# Search for a record in the slugs table using the specified slug.
|
90
|
-
def find_one(id)
|
91
|
-
return super(id) if id.unfriendly_id?
|
92
|
-
where(@klass.friendly_id_config.query_field => id).first or
|
93
|
-
with_old_friendly_id(id) {|x| where(:id => x).first} or
|
94
|
-
find_one_without_friendly_id(id)
|
95
|
-
end
|
96
|
-
|
97
|
-
# Search for a record in the slugs table using the specified slug.
|
98
|
-
def exists?(id = false)
|
99
|
-
return super if id.unfriendly_id?
|
100
|
-
exists_without_friendly_id?(@klass.friendly_id_config.query_field => id) or
|
101
|
-
with_old_friendly_id(id) {|x| exists_without_friendly_id?(:id => x)} or
|
102
|
-
exists_without_friendly_id?(id)
|
103
|
-
end
|
104
|
-
|
105
|
-
private
|
106
|
-
|
107
|
-
# Accepts a slug, and yields a corresponding sluggable_id into the block.
|
108
|
-
def with_old_friendly_id(slug, &block)
|
109
|
-
sql = "SELECT sluggable_id FROM #{Slug.quoted_table_name} WHERE sluggable_type = %s AND slug = %s"
|
110
|
-
sql = sql % [@klass.base_class.to_s, slug].map {|x| connection.quote(x)}
|
111
|
-
sluggable_ids = connection.select_values(sql)
|
112
|
-
yield sluggable_ids if sluggable_ids
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# This module overrides {FriendlyId::SlugGenerator#conflicts} to consider
|
117
|
-
# all historic slugs for that model.
|
118
|
-
module SlugGenerator
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
def conflicts
|
123
|
-
sluggable_class = friendly_id_config.model_class.base_class
|
124
|
-
pkey = sluggable_class.primary_key
|
125
|
-
value = sluggable.send pkey
|
126
|
-
|
127
|
-
scope = Slug.where("slug = ? OR slug LIKE ?", normalized, wildcard)
|
128
|
-
scope = scope.where(:sluggable_type => sluggable_class.to_s)
|
129
|
-
scope = scope.where("sluggable_id <> ?", value) unless sluggable.new_record?
|
130
|
-
if sluggable.friendly_id_config.uses?(:scoped)
|
131
|
-
scope = scope.where("scope = ?", sluggable.serialized_scope)
|
132
|
-
end
|
133
|
-
length_command = "LENGTH"
|
134
|
-
length_command = "LEN" if sluggable.connection.adapter_name =~ /sqlserver/i
|
135
|
-
scope.order("#{length_command}(slug) DESC, slug DESC")
|
136
|
-
end
|
137
|
-
end
|
138
100
|
end
|
139
101
|
end
|