friendly_id 3.3.3.0 → 4.0.0.beta7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/.travis.yml +24 -0
- data/.yardopts +4 -0
- data/Changelog.md +9 -10
- data/README.md +39 -48
- data/Rakefile +56 -58
- data/WhatsNew.md +95 -0
- data/bench.rb +63 -0
- data/friendly_id.gemspec +40 -0
- data/gemfiles/Gemfile.rails-3.0.rb +18 -0
- data/gemfiles/Gemfile.rails-3.0.rb.lock +52 -0
- data/gemfiles/Gemfile.rails-3.1.rb +18 -0
- data/gemfiles/Gemfile.rails-3.1.rb.lock +57 -0
- data/lib/friendly_id.rb +126 -80
- data/lib/friendly_id/active_record_adapter/relation.rb +10 -2
- data/lib/friendly_id/active_record_adapter/slugged_model.rb +3 -9
- data/lib/friendly_id/base.rb +132 -0
- data/lib/friendly_id/configuration.rb +65 -152
- data/lib/friendly_id/finder_methods.rb +20 -0
- data/lib/friendly_id/history.rb +88 -0
- data/lib/friendly_id/migration.rb +18 -0
- data/lib/friendly_id/model.rb +22 -0
- data/lib/friendly_id/object_utils.rb +40 -0
- data/lib/friendly_id/reserved.rb +46 -0
- data/lib/friendly_id/scoped.rb +131 -0
- data/lib/friendly_id/slug.rb +9 -0
- data/lib/friendly_id/slug_sequencer.rb +82 -0
- data/lib/friendly_id/slugged.rb +191 -76
- data/lib/friendly_id/version.rb +2 -2
- data/test/base_test.rb +54 -0
- data/test/configuration_test.rb +27 -0
- data/test/core_test.rb +30 -0
- data/test/databases.yml +19 -0
- data/test/helper.rb +88 -0
- data/test/history_test.rb +55 -0
- data/test/object_utils_test.rb +26 -0
- data/test/reserved_test.rb +26 -0
- data/test/schema.rb +59 -0
- data/test/scoped_test.rb +57 -0
- data/test/shared.rb +118 -0
- data/test/slugged_test.rb +83 -0
- data/test/sti_test.rb +48 -0
- metadata +110 -102
- data/Contributors.md +0 -46
- data/Guide.md +0 -626
- data/extras/README.txt +0 -3
- data/extras/bench.rb +0 -40
- data/extras/extras.rb +0 -38
- data/extras/prof.rb +0 -19
- data/extras/template-gem.rb +0 -26
- data/extras/template-plugin.rb +0 -28
- data/generators/friendly_id/friendly_id_generator.rb +0 -30
- data/generators/friendly_id/templates/create_slugs.rb +0 -18
- data/lib/tasks/friendly_id.rake +0 -19
- data/rails/init.rb +0 -2
- data/test/active_record_adapter/ar_test_helper.rb +0 -149
- data/test/active_record_adapter/basic_slugged_model_test.rb +0 -14
- data/test/active_record_adapter/cached_slug_test.rb +0 -76
- data/test/active_record_adapter/core.rb +0 -138
- data/test/active_record_adapter/custom_normalizer_test.rb +0 -20
- data/test/active_record_adapter/custom_table_name_test.rb +0 -22
- data/test/active_record_adapter/default_scope_test.rb +0 -30
- data/test/active_record_adapter/optimistic_locking_test.rb +0 -18
- data/test/active_record_adapter/scoped_model_test.rb +0 -129
- data/test/active_record_adapter/simple_test.rb +0 -76
- data/test/active_record_adapter/slug_test.rb +0 -34
- data/test/active_record_adapter/slugged.rb +0 -33
- data/test/active_record_adapter/slugged_status_test.rb +0 -28
- data/test/active_record_adapter/sti_test.rb +0 -22
- data/test/active_record_adapter/support/database.jdbcsqlite3.yml +0 -2
- data/test/active_record_adapter/support/database.mysql.yml +0 -4
- data/test/active_record_adapter/support/database.mysql2.yml +0 -4
- data/test/active_record_adapter/support/database.postgres.yml +0 -6
- data/test/active_record_adapter/support/database.sqlite3.yml +0 -2
- data/test/active_record_adapter/support/models.rb +0 -104
- data/test/active_record_adapter/tasks_test.rb +0 -82
- data/test/compatibility/ancestry/Gemfile.lock +0 -34
- data/test/friendly_id_test.rb +0 -96
- data/test/test_helper.rb +0 -13
@@ -124,8 +124,8 @@ module FriendlyId
|
|
124
124
|
if result.size == expected_size
|
125
125
|
result
|
126
126
|
else
|
127
|
-
conditions = arel.
|
128
|
-
conditions = " [#{conditions}]" if conditions
|
127
|
+
conditions = arel.send(:where_clauses).join(', ')
|
128
|
+
conditions = " [WHERE #{conditions}]" if conditions.present?
|
129
129
|
error = "Couldn't find all #{klass.name.pluralize} with IDs "
|
130
130
|
error << "(#{ids.join(", ")})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
|
131
131
|
raise ActiveRecord::RecordNotFound, error
|
@@ -141,6 +141,14 @@ module FriendlyId
|
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
|
+
def apply_finder_options(options)
|
145
|
+
if options[:scope]
|
146
|
+
raise "The :scope finder option has been removed from FriendlyId 3.2.0 " +
|
147
|
+
"https://github.com/norman/friendly_id/issues#issue/88"
|
148
|
+
end
|
149
|
+
super
|
150
|
+
end
|
151
|
+
|
144
152
|
protected
|
145
153
|
|
146
154
|
def find_one(id)
|
@@ -4,19 +4,13 @@ module FriendlyId
|
|
4
4
|
|
5
5
|
def self.included(base)
|
6
6
|
base.class_eval do
|
7
|
-
has_one :slug, :order => 'id DESC', :as => :sluggable, :dependent => :nullify
|
8
7
|
has_many :slugs, :order => 'id DESC', :as => :sluggable, :dependent => :destroy
|
8
|
+
has_one :slug, :order => 'id DESC', :as => :sluggable, :dependent => :nullify
|
9
9
|
before_save :build_a_slug
|
10
10
|
after_save :set_slug_cache
|
11
11
|
after_update :update_scope
|
12
12
|
after_update :update_dependent_scopes
|
13
13
|
protect_friendly_id_attributes
|
14
|
-
|
15
|
-
def slug_with_rails_3_2_patch
|
16
|
-
slug_without_rails_3_2_patch || slugs.first
|
17
|
-
end
|
18
|
-
|
19
|
-
alias_method_chain :slug, :rails_3_2_patch
|
20
14
|
end
|
21
15
|
end
|
22
16
|
|
@@ -80,7 +74,7 @@ module FriendlyId
|
|
80
74
|
slug.scope = send(friendly_id_config.scope).to_param
|
81
75
|
similar = Slug.similar_to(slug)
|
82
76
|
if !similar.empty?
|
83
|
-
slug.sequence = similar.
|
77
|
+
slug.sequence = similar.first.sequence.succ
|
84
78
|
end
|
85
79
|
slug.save!
|
86
80
|
end
|
@@ -104,7 +98,7 @@ module FriendlyId
|
|
104
98
|
end
|
105
99
|
|
106
100
|
# This method was removed in ActiveRecord 3.0.
|
107
|
-
if
|
101
|
+
if !ActiveRecord::Base.private_method_defined? :update_without_callbacks
|
108
102
|
def update_without_callbacks
|
109
103
|
attributes_with_values = arel_attributes_values(false, false, attribute_names)
|
110
104
|
return false if attributes_with_values.empty?
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
# Class methods that will be added to model classes that extend {FriendlyId}.
|
3
|
+
module Base
|
4
|
+
|
5
|
+
# Configure FriendlyId's behavior in a model.
|
6
|
+
#
|
7
|
+
# class Post < ActiveRecord::Base
|
8
|
+
# extend FriendlyId
|
9
|
+
# friendly_id :title, :use => :slugged
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# When given the optional block, this method will yield the class's instance
|
13
|
+
# of {FriendlyId::Configuration} to the block before evaluating other
|
14
|
+
# arguments, so configuration values set in the block may be overwritten by
|
15
|
+
# the arguments. This order was chosen to allow passing the same proc to
|
16
|
+
# multiple models, while being able to override the values it sets. Here is
|
17
|
+
# a contrived example:
|
18
|
+
#
|
19
|
+
# $friendly_id_config_proc = Proc.new do |config|
|
20
|
+
# config.base = :name
|
21
|
+
# config.use :slugged
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# class Foo < ActiveRecord::Base
|
25
|
+
# extend FriendlyId
|
26
|
+
# friendly_id &$friendly_id_config_proc
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# class Bar < ActiveRecord::Base
|
30
|
+
# extend FriendlyId
|
31
|
+
# friendly_id :title, &$friendly_id_config_proc
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# However, it's usually better to use {FriendlyId.defaults} for this:
|
35
|
+
#
|
36
|
+
# FriendlyId.defaults do |config|
|
37
|
+
# config.base = :name
|
38
|
+
# config.use :slugged
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# class Foo < ActiveRecord::Base
|
42
|
+
# extend FriendlyId
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# class Bar < ActiveRecord::Base
|
46
|
+
# extend FriendlyId
|
47
|
+
# friendly_id :title
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# In general you should use the block syntax either because of your personal
|
51
|
+
# aesthetic preference, or because you need to share some functionality
|
52
|
+
# between multiple models that can't be well encapsulated by
|
53
|
+
# {FriendlyId.defaults}.
|
54
|
+
#
|
55
|
+
# === Order Method Calls in a Block vs Ordering Options
|
56
|
+
#
|
57
|
+
# When calling this method without a block, you may set the hash options in
|
58
|
+
# any order.
|
59
|
+
#
|
60
|
+
# However, when using block-style invocation, be sure to call
|
61
|
+
# FriendlyId::Configuration's {FriendlyId::Configuration#use use} method
|
62
|
+
# *prior* to the associated configuration options, because it will include
|
63
|
+
# modules into your class, and these modules in turn may add required
|
64
|
+
# configuration options to the +@friendly_id_configuraton+'s class:
|
65
|
+
#
|
66
|
+
# class Person < ActiveRecord::Base
|
67
|
+
# friendly_id do |config|
|
68
|
+
# # This will work
|
69
|
+
# config.use :slugged
|
70
|
+
# config.sequence_separator = ":"
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# class Person < ActiveRecord::Base
|
75
|
+
# friendly_id do |config|
|
76
|
+
# # This will fail
|
77
|
+
# config.sequence_separator = ":"
|
78
|
+
# config.use :slugged
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# @option options [Symbol] :use The name of an addon to use. By default,
|
83
|
+
# FriendlyId provides {FriendlyId::Slugged :slugged},
|
84
|
+
# {FriendlyId::History :history}, {FriendlyId::Reserved :reserved}, and
|
85
|
+
# {FriendlyId::Scoped :scoped}.
|
86
|
+
#
|
87
|
+
# @option options [Array] :reserved_words Available when using +:reserved+,
|
88
|
+
# which is loaded by default. Sets an array of words banned for use as
|
89
|
+
# the basis of a friendly_id. By default this includes "edit" and "new".
|
90
|
+
#
|
91
|
+
# @option options [Symbol] :scope Available when using +:scoped+.
|
92
|
+
# Sets the relation or column used to scope generated friendly ids. This
|
93
|
+
# option has no default value.
|
94
|
+
#
|
95
|
+
# @option options [Symbol] :sequence_separator Available when using +:slugged+.
|
96
|
+
# Configures the sequence of characters used to separate a slug from a
|
97
|
+
# sequence. Defaults to +--+.
|
98
|
+
#
|
99
|
+
# @option options [Symbol] :slug_column Available when using +:slugged+.
|
100
|
+
# Configures the name of the column where FriendlyId will store the slug.
|
101
|
+
# Defaults to +:slug+.
|
102
|
+
#
|
103
|
+
# @option options [Symbol] :slug_sequencer_class Available when using +:slugged+.
|
104
|
+
# Sets the class used to generate unique slugs. You should not specify this
|
105
|
+
# unless you're doing some extensive hacking on FriendlyId. Defaults to
|
106
|
+
# {FriendlyId::SlugSequencer}.
|
107
|
+
#
|
108
|
+
# @yield Provides access to the model class's friendly_id_config, which
|
109
|
+
# allows an alternate configuration syntax, and conditional configuration
|
110
|
+
# logic.
|
111
|
+
#
|
112
|
+
# @yieldparam config The model class's {FriendlyId::Configuration friendly_id_config}.
|
113
|
+
def friendly_id(base = nil, options = {}, &block)
|
114
|
+
yield @friendly_id_config if block_given?
|
115
|
+
@friendly_id_config.use options.delete :use
|
116
|
+
@friendly_id_config.send :set, base ? options.merge(:base => base) : options
|
117
|
+
before_save {|rec| rec.instance_eval {@current_friendly_id = friendly_id}}
|
118
|
+
include Model
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns the model class's {FriendlyId::Configuration friendly_id_config}.
|
122
|
+
# @note In the case of Single Table Inheritance (STI), this method will
|
123
|
+
# duplicate the parent class's FriendlyId::Configuration instance on first
|
124
|
+
# access. If you're concerned about thread safety, then be sure to invoke
|
125
|
+
# {#friendly_id} in your class for each model.
|
126
|
+
def friendly_id_config
|
127
|
+
@friendly_id_config or begin
|
128
|
+
@friendly_id_config = base_class.friendly_id_config.dup
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -1,166 +1,79 @@
|
|
1
1
|
module FriendlyId
|
2
|
-
|
3
|
-
#
|
4
|
-
# by `has_friendly_id` to store a model's configuration and
|
5
|
-
# configuration-related methods.
|
6
|
-
#
|
7
|
-
# The arguments accepted by +has_friendly_id+ correspond to the writeable
|
8
|
-
# instance attributes of this class; please see the description of the
|
9
|
-
# attributes below for information on the possible options.
|
10
|
-
#
|
11
|
-
# @example
|
12
|
-
# has_friendly_id :name,
|
13
|
-
# :use_slug => true,
|
14
|
-
# :max_length => 150,
|
15
|
-
# :approximate_ascii => true,
|
16
|
-
# :ascii_approximation_options => :german,
|
17
|
-
# :sequence_separator => ":",
|
18
|
-
# :reserved_words => ["reserved", "words"],
|
19
|
-
# :scope => :country,
|
20
|
-
# :cache_column => :my_cache_column_name
|
21
|
-
# # etc.
|
2
|
+
# The configuration paramters passed to +friendly_id+ will be stored in
|
3
|
+
# this object.
|
22
4
|
class Configuration
|
23
5
|
|
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
|
-
# The
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
#
|
53
|
-
attr_reader :
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
# Array of words that are reserved and can't be used as friendly_id strings.
|
61
|
-
# If a listed word is used in a sluggable model, it will raise a
|
62
|
-
# FriendlyId::SlugGenerationError. For Rails applications, you are recommended
|
63
|
-
# to include "index" and "new", which used as the defaults unless overridden.
|
64
|
-
attr_accessor :reserved_words
|
65
|
-
|
66
|
-
# The method or relation to use as the friendly_id's scope.
|
67
|
-
attr_reader :scope
|
68
|
-
|
69
|
-
# The string that separates slug names from slug sequences. Defaults to "--".
|
70
|
-
attr_accessor :sequence_separator
|
71
|
-
|
72
|
-
# Strip non-ASCII characters from the friendly_id string.
|
73
|
-
attr_accessor :strip_non_ascii
|
74
|
-
|
75
|
-
# Use slugs for storing the friendly_id string.
|
76
|
-
attr_accessor :use_slug
|
77
|
-
alias :use_slugs= :use_slug
|
78
|
-
|
79
|
-
def initialize(configured_class, method, options = nil, &block)
|
80
|
-
@configured_class = configured_class
|
81
|
-
@method = method.to_sym
|
82
|
-
DEFAULTS.merge(options || {}).each do |key, value|
|
83
|
-
self.send "#{key}=".to_sym, value
|
84
|
-
end
|
85
|
-
yield self if block_given?
|
86
|
-
end
|
87
|
-
|
88
|
-
def cache_column=(value)
|
89
|
-
@cache_column = value.to_s.strip.to_sym
|
90
|
-
if value =~ /\s/ || [:slug, :slugs].include?(@cache_column)
|
91
|
-
raise ArgumentError, "FriendlyId cache column can not be named '#{value}'"
|
92
|
-
end
|
93
|
-
@cache_column
|
94
|
-
end
|
95
|
-
|
96
|
-
# This should be overridden by adapters that implement caching.
|
97
|
-
def cache_column?
|
98
|
-
false
|
6
|
+
# The base column or method used by FriendlyId as the basis of a friendly id
|
7
|
+
# or slug.
|
8
|
+
#
|
9
|
+
# For models that don't use FriendlyId::Slugged, the base is the column that
|
10
|
+
# is used as the FriendlyId directly. For models using FriendlyId::Slugged,
|
11
|
+
# the base is a column or method whose value is used as the basis of the
|
12
|
+
# slug.
|
13
|
+
#
|
14
|
+
# For example, if you have a model representing blog posts and that uses
|
15
|
+
# slugs, you likely will want to use the "title" attribute as the base, and
|
16
|
+
# FriendlyId will take care of transforming the human-readable title into
|
17
|
+
# something suitable for use in a URL.
|
18
|
+
#
|
19
|
+
# @param [Symbol] A symbol referencing a column or method in the model. This
|
20
|
+
# value is usually set by passing it as the first argument to
|
21
|
+
# {FriendlyId::Base#friendly_id friendly_id}:
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# class Book < ActiveRecord::Base
|
25
|
+
# extend FriendlyId
|
26
|
+
# friendly_id :name
|
27
|
+
# end
|
28
|
+
attr_accessor :base
|
29
|
+
|
30
|
+
# The default configuration options.
|
31
|
+
attr_reader :defaults
|
32
|
+
|
33
|
+
# The model class that this configuration belongs to.
|
34
|
+
# @return ActiveRecord::Base
|
35
|
+
attr_reader :model_class
|
36
|
+
|
37
|
+
def initialize(model_class, values = nil)
|
38
|
+
@model_class = model_class
|
39
|
+
@defaults = {}
|
40
|
+
set values
|
99
41
|
end
|
100
42
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
43
|
+
# Lets you specify the modules to use with FriendlyId.
|
44
|
+
#
|
45
|
+
# This method is invoked by {FriendlyId::Base#friendly_id friendly_id} when
|
46
|
+
# passing the +:use+ option, or when using {FriendlyId::Base#friendly_id
|
47
|
+
# friendly_id} with a block.
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# class Book < ActiveRecord::Base
|
51
|
+
# extend FriendlyId
|
52
|
+
# friendly_id :name, :use => :slugged
|
53
|
+
# end
|
54
|
+
# @param [#to_s] *modules Arguments should be a symbols or strings that
|
55
|
+
# correspond with the name of a module inside the FriendlyId namespace. By
|
56
|
+
# default FriendlyId provides +:slugged+, +:history+ and +:scoped+.
|
57
|
+
def use(*modules)
|
58
|
+
modules.to_a.flatten.compact.map do |name|
|
59
|
+
mod = FriendlyId.const_get(name.to_s.classify)
|
60
|
+
model_class.send(:include, mod) unless model_class < mod
|
106
61
|
end
|
107
62
|
end
|
108
63
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
def reserved_error_message(word)
|
119
|
-
[method, reserved_message % word] if reserved? word
|
120
|
-
end
|
121
|
-
|
122
|
-
def scope=(scope)
|
123
|
-
self.class.scopes_used = true
|
124
|
-
@scope = scope
|
125
|
-
end
|
126
|
-
|
127
|
-
def sequence_separator=(string)
|
128
|
-
if string == "-" || string =~ /\s/
|
129
|
-
raise ArgumentError, "FriendlyId sequence_separator can not be '#{string}'"
|
130
|
-
end
|
131
|
-
@sequence_separator = string
|
132
|
-
end
|
133
|
-
|
134
|
-
# This will be set if FriendlyId's scope feature is used in any model. It is here
|
135
|
-
# to provide a way to avoid invoking costly scope lookup methods when the scoped
|
136
|
-
# slug feature is not being used by any models.
|
137
|
-
def self.scopes_used=(val)
|
138
|
-
@scopes_used = !!val
|
139
|
-
end
|
140
|
-
|
141
|
-
# Are scoped slugs being used by any model?
|
142
|
-
# @see Configuration.scoped_used=
|
143
|
-
def self.scopes_used?
|
144
|
-
@scopes_used
|
145
|
-
end
|
146
|
-
|
147
|
-
%w[approximate_ascii scope strip_non_ascii use_slug].each do |method|
|
148
|
-
class_eval(<<-EOM, __FILE__, __LINE__ + 1)
|
149
|
-
def #{method}?
|
150
|
-
!! #{method}
|
151
|
-
end
|
152
|
-
EOM
|
64
|
+
# The column that FriendlyId will use to find the record when querying by
|
65
|
+
# friendly id.
|
66
|
+
#
|
67
|
+
# This method is generally only used internally by FriendlyId.
|
68
|
+
# @return String
|
69
|
+
def query_field
|
70
|
+
base.to_s
|
153
71
|
end
|
154
72
|
|
155
|
-
|
73
|
+
private
|
156
74
|
|
157
|
-
def
|
158
|
-
{
|
159
|
-
:to_ascii => strip_non_ascii?,
|
160
|
-
:transliterate => approximate_ascii?,
|
161
|
-
:transliterations => ascii_approximation_options,
|
162
|
-
:max_length => max_length
|
163
|
-
}
|
75
|
+
def set(values)
|
76
|
+
values and values.each {|name, value| self.send "#{name}=", value}
|
164
77
|
end
|
165
78
|
end
|
166
79
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
# These methods will override the finder methods in ActiveRecord::Relation.
|
3
|
+
module FinderMethods
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
# FriendlyId overrides this method to make it possible to use friendly id's
|
8
|
+
# identically to numeric ids in finders.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# person = Person.find(123)
|
12
|
+
# person = Person.find("joe")
|
13
|
+
#
|
14
|
+
# @see FriendlyId::ObjectUtils
|
15
|
+
def find_one(id)
|
16
|
+
return super if !@klass.respond_to?(:friendly_id) || id.unfriendly_id?
|
17
|
+
where(@klass.friendly_id_config.query_field => id).first or super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|