cmassimo-friendly_id 3.0.4.2
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.
- data/Changelog.md +277 -0
- data/Contributors.md +39 -0
- data/Guide.md +561 -0
- data/LICENSE +19 -0
- data/README.md +83 -0
- data/Rakefile +66 -0
- data/extras/README.txt +3 -0
- data/extras/bench.rb +36 -0
- data/extras/extras.rb +38 -0
- data/extras/prof.rb +14 -0
- data/extras/template-gem.rb +26 -0
- data/extras/template-plugin.rb +28 -0
- data/generators/friendly_id/friendly_id_generator.rb +30 -0
- data/generators/friendly_id/templates/create_slugs.rb +18 -0
- data/lib/friendly_id.rb +73 -0
- data/lib/friendly_id/active_record.rb +52 -0
- data/lib/friendly_id/active_record_adapter/configuration.rb +67 -0
- data/lib/friendly_id/active_record_adapter/finders.rb +156 -0
- data/lib/friendly_id/active_record_adapter/simple_model.rb +123 -0
- data/lib/friendly_id/active_record_adapter/slug.rb +66 -0
- data/lib/friendly_id/active_record_adapter/slugged_model.rb +238 -0
- data/lib/friendly_id/active_record_adapter/tasks.rb +69 -0
- data/lib/friendly_id/configuration.rb +113 -0
- data/lib/friendly_id/finders.rb +109 -0
- data/lib/friendly_id/railtie.rb +20 -0
- data/lib/friendly_id/sequel.rb +5 -0
- data/lib/friendly_id/slug_string.rb +391 -0
- data/lib/friendly_id/slugged.rb +102 -0
- data/lib/friendly_id/status.rb +35 -0
- data/lib/friendly_id/test.rb +291 -0
- data/lib/friendly_id/version.rb +9 -0
- data/lib/generators/friendly_id_generator.rb +25 -0
- data/lib/tasks/friendly_id.rake +19 -0
- data/rails/init.rb +2 -0
- data/test/active_record_adapter/ar_test_helper.rb +119 -0
- data/test/active_record_adapter/basic_slugged_model_test.rb +14 -0
- data/test/active_record_adapter/cached_slug_test.rb +61 -0
- data/test/active_record_adapter/core.rb +98 -0
- data/test/active_record_adapter/custom_normalizer_test.rb +20 -0
- data/test/active_record_adapter/custom_table_name_test.rb +22 -0
- data/test/active_record_adapter/scoped_model_test.rb +118 -0
- data/test/active_record_adapter/simple_test.rb +76 -0
- data/test/active_record_adapter/slug_test.rb +34 -0
- data/test/active_record_adapter/slugged.rb +30 -0
- data/test/active_record_adapter/slugged_status_test.rb +25 -0
- data/test/active_record_adapter/sti_test.rb +22 -0
- data/test/active_record_adapter/support/database.jdbcsqlite3.yml +2 -0
- data/test/active_record_adapter/support/database.mysql.yml +4 -0
- data/test/active_record_adapter/support/database.postgres.yml +6 -0
- data/test/active_record_adapter/support/database.sqlite3.yml +2 -0
- data/test/active_record_adapter/support/models.rb +87 -0
- data/test/active_record_adapter/tasks_test.rb +82 -0
- data/test/friendly_id_test.rb +55 -0
- data/test/slug_string_test.rb +88 -0
- data/test/test_helper.rb +15 -0
- metadata +168 -0
@@ -0,0 +1,238 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
module ActiveRecordAdapter
|
3
|
+
module SluggedModel
|
4
|
+
|
5
|
+
module SluggedFinder
|
6
|
+
# Whether :include => :slugs has been passed as an option.
|
7
|
+
def slugs_included?
|
8
|
+
[*(options[:include] or [])].flatten.include?(:slugs)
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle_friendly_result
|
12
|
+
raise ::ActiveRecord::RecordNotFound.new unless @result
|
13
|
+
@result.friendly_id_status.friendly_id = id
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class MultipleFinder
|
19
|
+
|
20
|
+
include FriendlyId::ActiveRecordAdapter::Finders::Multiple
|
21
|
+
include SluggedFinder
|
22
|
+
|
23
|
+
attr_reader :slugs
|
24
|
+
|
25
|
+
def find
|
26
|
+
@results = model_class.scoped(find_options).all(options).uniq
|
27
|
+
raise ::ActiveRecord::RecordNotFound, error_message if @results.size != expected_size
|
28
|
+
@results.each {|result| result.friendly_id_status.name = slug_for(result)}
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def find_conditions
|
34
|
+
"%s IN (%s)" % [
|
35
|
+
"#{quoted_table_name}.#{primary_key}",
|
36
|
+
(unfriendly_ids + sluggable_ids).join(",")
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_options
|
41
|
+
{:select => "#{quoted_table_name}.*", :conditions => find_conditions,
|
42
|
+
:joins => slugs_included? ? options[:joins] : :slugs}
|
43
|
+
end
|
44
|
+
|
45
|
+
def sluggable_ids
|
46
|
+
@sluggable_ids ||= slugs.map(&:sluggable_id)
|
47
|
+
end
|
48
|
+
|
49
|
+
def slugs
|
50
|
+
@slugs ||= friendly_ids.map do |friendly_id|
|
51
|
+
name, sequence = friendly_id.parse_friendly_id(friendly_id_config.sequence_separator)
|
52
|
+
Slug.first :conditions => {
|
53
|
+
:name => name,
|
54
|
+
:scope => scope,
|
55
|
+
:sequence => sequence,
|
56
|
+
:sluggable_type => base_class.name
|
57
|
+
}
|
58
|
+
end.compact
|
59
|
+
end
|
60
|
+
|
61
|
+
def slug_for(result)
|
62
|
+
slugs.detect {|slug| result.id == slug.sluggable_id}
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# Performs a find a single friendly_id using the cached_slug column,
|
68
|
+
# if available. This is significantly faster, and can be used in all
|
69
|
+
# circumstances unless the +:scope+ argument is present.
|
70
|
+
class CachedMultipleFinder < SimpleModel::MultipleFinder
|
71
|
+
# The column used to store the cached slug.
|
72
|
+
def column
|
73
|
+
"#{table_name}.#{friendly_id_config.cache_column}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class SingleFinder
|
78
|
+
|
79
|
+
include FriendlyId::Finders::Base
|
80
|
+
include FriendlyId::Finders::Single
|
81
|
+
include SluggedFinder
|
82
|
+
|
83
|
+
def find
|
84
|
+
@result = model_class.scoped(find_options).first(options)
|
85
|
+
handle_friendly_result if friendly?
|
86
|
+
@result
|
87
|
+
rescue ::ActiveRecord::RecordNotFound => @error
|
88
|
+
friendly_id_config.scope? ? raise_scoped_error : (raise @error)
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def find_options
|
94
|
+
slug_table = Slug.table_name
|
95
|
+
{
|
96
|
+
:select => "#{model_class.quoted_table_name}.*",
|
97
|
+
:joins => slugs_included? ? options[:joins] : :slugs,
|
98
|
+
:conditions => {
|
99
|
+
"#{slug_table}.name" => name,
|
100
|
+
"#{slug_table}.scope" => scope,
|
101
|
+
"#{slug_table}.sequence" => sequence
|
102
|
+
}
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
def raise_scoped_error
|
107
|
+
scope_message = scope || "expected, but none given"
|
108
|
+
message = "%s, scope: %s" % [@error.message, scope_message]
|
109
|
+
raise ::ActiveRecord::RecordNotFound, message
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
# Performs a find for multiple friendly_ids using the cached_slug column,
|
115
|
+
# if available. This is significantly faster, and can be used in all
|
116
|
+
# circumstances unless the +:scope+ argument is present.
|
117
|
+
class CachedSingleFinder < SimpleModel::SingleFinder
|
118
|
+
|
119
|
+
include SluggedFinder
|
120
|
+
|
121
|
+
def find
|
122
|
+
@result = model_class.scoped(find_options).first(options)
|
123
|
+
handle_friendly_result if friendly?
|
124
|
+
@result
|
125
|
+
rescue ActiveRecord::RecordNotFound
|
126
|
+
SingleFinder.new(id, model_class, options).find
|
127
|
+
end
|
128
|
+
|
129
|
+
# The column used to store the cached slug.
|
130
|
+
def column
|
131
|
+
"#{table_name}.#{friendly_id_config.cache_column}"
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.included(base)
|
137
|
+
base.class_eval do
|
138
|
+
has_many :slugs, :order => 'id DESC', :as => :sluggable, :dependent => :destroy
|
139
|
+
before_create :build_slug
|
140
|
+
after_create :set_slug_cache
|
141
|
+
after_update :update_scope
|
142
|
+
after_update :update_dependent_scopes
|
143
|
+
after_update :update_slug_from_cache
|
144
|
+
protect_friendly_id_attributes
|
145
|
+
extend FriendlyId::ActiveRecordAdapter::FinderMethods
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
include FriendlyId::Slugged::Model
|
150
|
+
|
151
|
+
def find_slug(name, sequence)
|
152
|
+
slugs.find_by_name_and_sequence(name, sequence)
|
153
|
+
end
|
154
|
+
|
155
|
+
# The model instance's current {FriendlyId::ActiveRecordAdapter::Slug slug}.
|
156
|
+
def slug
|
157
|
+
return @slug if new_record?
|
158
|
+
@slug ||= slugs.first(:order => "id DESC")
|
159
|
+
end
|
160
|
+
|
161
|
+
# Set the slug.
|
162
|
+
def slug=(slug)
|
163
|
+
@new_friendly_id = slug.to_friendly_id unless slug.nil?
|
164
|
+
super
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns the friendly id, or if none is available, the numeric id.
|
168
|
+
def to_param
|
169
|
+
friendly_id_config.cache_column ? to_param_from_cache : to_param_from_slug
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def scope_changed?
|
175
|
+
friendly_id_config.scope? && send(friendly_id_config.scope).to_param != slug.scope
|
176
|
+
end
|
177
|
+
|
178
|
+
# Respond with the cached value if available.
|
179
|
+
def to_param_from_cache
|
180
|
+
read_attribute(friendly_id_config.cache_column) || id.to_s
|
181
|
+
end
|
182
|
+
|
183
|
+
# Respond with the slugged value if available.
|
184
|
+
def to_param_from_slug
|
185
|
+
slug? ? slug.to_friendly_id : id.to_s
|
186
|
+
end
|
187
|
+
|
188
|
+
# Build the new slug using the generated friendly id.
|
189
|
+
def build_slug
|
190
|
+
return unless new_slug_needed?
|
191
|
+
self.slug = slugs.build :name => slug_text.to_s, :scope => friendly_id_config.scope_for(self)
|
192
|
+
end
|
193
|
+
|
194
|
+
# Reset the cached friendly_id?
|
195
|
+
def new_cache_needed?
|
196
|
+
uses_slug_cache? && slug? && send(friendly_id_config.cache_column) != slug.to_friendly_id
|
197
|
+
end
|
198
|
+
|
199
|
+
# Reset the cached friendly_id.
|
200
|
+
def set_slug_cache
|
201
|
+
if new_cache_needed?
|
202
|
+
send "#{friendly_id_config.cache_column}=", slug.to_friendly_id
|
203
|
+
send :update_without_callbacks
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def update_scope
|
208
|
+
return unless slug && scope_changed?
|
209
|
+
slug.update_attributes :scope => send(friendly_id_config.scope).to_param
|
210
|
+
rescue ActiveRecord::StatementInvalid
|
211
|
+
slug.update_attributes :sequence => Slug.similar_to(slug).first.sequence.succ
|
212
|
+
end
|
213
|
+
|
214
|
+
# Update the slugs for any model that is using this model as its
|
215
|
+
# FriendlyId scope.
|
216
|
+
def update_dependent_scopes
|
217
|
+
if slugs(true).size > 1 && @new_friendly_id
|
218
|
+
friendly_id_config.child_scopes.each do |klass|
|
219
|
+
Slug.update_all "scope = '#{@new_friendly_id}'", ["sluggable_type = ? AND scope = ?",
|
220
|
+
klass.to_s, slugs.second.to_friendly_id]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Creates a new slug when the cached friendly_id is modified
|
226
|
+
def update_slug_from_cache
|
227
|
+
if uses_slug_cache? && send("#{friendly_id_config.cache_column}_changed?")
|
228
|
+
self.slug = slugs.create :name => send(friendly_id_config.cache_column).to_s, :scope => friendly_id_config.scope_for(self)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
# Does the model use slug caching?
|
232
|
+
def uses_slug_cache?
|
233
|
+
friendly_id_config.cache_column?
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
class TaskRunner
|
3
|
+
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
attr_accessor :days
|
7
|
+
attr_accessor :klass
|
8
|
+
attr_accessor :task_options
|
9
|
+
|
10
|
+
def_delegators :klass, :find, :friendly_id_config, :update_all
|
11
|
+
|
12
|
+
OLD_SLUG_DAYS = 45
|
13
|
+
|
14
|
+
def initialize(&block)
|
15
|
+
self.klass = ENV["MODEL"]
|
16
|
+
self.days = ENV["DAYS"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def days=(days)
|
20
|
+
@days ||= days.blank? ? OLD_SLUG_DAYS : days.to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def klass=(klass)
|
24
|
+
@klass ||= klass.to_s.classify.constantize unless klass.blank?
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_slugs
|
28
|
+
validate_uses_slugs
|
29
|
+
cond = "slugs.id IS NULL"
|
30
|
+
options = {:limit => 100, :include => :slugs, :conditions => cond, :order => "#{klass.table_name}.id ASC"}.merge(task_options || {})
|
31
|
+
while records = find(:all, options) do
|
32
|
+
break if records.size == 0
|
33
|
+
records.each do |record|
|
34
|
+
record.save(:validate => false)
|
35
|
+
yield(record) if block_given?
|
36
|
+
end
|
37
|
+
options[:conditions] = cond + " and #{klass.table_name}.id > #{records.last.id}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_slugs
|
42
|
+
validate_uses_slugs
|
43
|
+
Slug.destroy_all(["sluggable_type = ?", klass.to_s])
|
44
|
+
if column = friendly_id_config.cache_column
|
45
|
+
update_all("#{column} = NULL")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete_old_slugs
|
50
|
+
conditions = ["created_at < ?", DateTime.now - days]
|
51
|
+
if klass
|
52
|
+
conditions[0] << " AND sluggable_type = ?"
|
53
|
+
conditions << klass.to_s
|
54
|
+
end
|
55
|
+
Slug.all(:conditions => conditions).select(&:outdated?).map(&:destroy)
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_uses_slugs
|
59
|
+
(raise "You need to pass a MODEL=<model name> argument to rake") if klass.blank?
|
60
|
+
unless friendly_id_config.use_slug?
|
61
|
+
raise "Class '%s' doesn't use slugs" % klass.to_s
|
62
|
+
end
|
63
|
+
rescue NoMethodError
|
64
|
+
raise "Class '%s' doesn't use FriendlyId" % klass.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
|
3
|
+
# This class is not intended to be used on its own, it is used internally
|
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.
|
22
|
+
class Configuration
|
23
|
+
|
24
|
+
DEFAULTS = {
|
25
|
+
:allow_nil => false,
|
26
|
+
:ascii_approximation_options => [],
|
27
|
+
:max_length => 255,
|
28
|
+
:reserved_words => ["index", "new"],
|
29
|
+
:reserved_message => 'can not be "%s"',
|
30
|
+
:sequence_separator => "--"
|
31
|
+
}
|
32
|
+
|
33
|
+
# Whether to allow friendly_id and/or slugs to be nil. This is not
|
34
|
+
# generally useful on its own, but may allow you greater flexibility to
|
35
|
+
# customize your application.
|
36
|
+
attr_accessor :allow_nil
|
37
|
+
alias :allow_nil? :allow_nil
|
38
|
+
|
39
|
+
# Strip diacritics from Western characters.
|
40
|
+
attr_accessor :approximate_ascii
|
41
|
+
|
42
|
+
# Locale-type options for ASCII approximations. These can be any of the
|
43
|
+
# values supported by {SlugString#approximate_ascii!}.
|
44
|
+
attr_accessor :ascii_approximation_options
|
45
|
+
|
46
|
+
# The class that's using the configuration.
|
47
|
+
attr_reader :configured_class
|
48
|
+
|
49
|
+
# The maximum allowed length for a friendly_id string. This is checked *after* a
|
50
|
+
# string is processed by FriendlyId to remove spaces, special characters, etc.
|
51
|
+
attr_accessor :max_length
|
52
|
+
|
53
|
+
# The method or column that will be used as the basis of the friendly_id string.
|
54
|
+
attr_reader :method
|
55
|
+
alias :column :method
|
56
|
+
|
57
|
+
# The message shown when a reserved word is used.
|
58
|
+
# @see #reserved_words
|
59
|
+
attr_accessor :reserved_message
|
60
|
+
|
61
|
+
# Array of words that are reserved and can't be used as friendly_id strings.
|
62
|
+
# If a listed word is used in a sluggable model, it will raise a
|
63
|
+
# FriendlyId::SlugGenerationError. For Rails applications, you are recommended
|
64
|
+
# to include "index" and "new", which used as the defaults unless overridden.
|
65
|
+
attr_accessor :reserved_words
|
66
|
+
|
67
|
+
# The method or relation to use as the friendly_id's scope.
|
68
|
+
attr_accessor :scope
|
69
|
+
|
70
|
+
# The string that separates slug names from slug sequences. Defaults to "--".
|
71
|
+
attr_accessor :sequence_separator
|
72
|
+
|
73
|
+
# Strip non-ASCII characters from the friendly_id string.
|
74
|
+
attr_accessor :strip_non_ascii
|
75
|
+
|
76
|
+
# Use slugs for storing the friendly_id string.
|
77
|
+
attr_accessor :use_slug
|
78
|
+
alias :use_slugs= :use_slug
|
79
|
+
|
80
|
+
def initialize(configured_class, method, options = nil, &block)
|
81
|
+
@configured_class = configured_class
|
82
|
+
@method = method.to_sym
|
83
|
+
DEFAULTS.merge(options || {}).each do |key, value|
|
84
|
+
self.send "#{key}=".to_sym, value
|
85
|
+
end
|
86
|
+
yield self if block_given?
|
87
|
+
end
|
88
|
+
|
89
|
+
def reserved_words=(*words)
|
90
|
+
@reserved_words = words.flatten.uniq
|
91
|
+
end
|
92
|
+
|
93
|
+
def reserved?(word)
|
94
|
+
reserved_words.include? word.to_s
|
95
|
+
end
|
96
|
+
|
97
|
+
def reserved_error_message(word)
|
98
|
+
[method, reserved_message % word] if reserved? word
|
99
|
+
end
|
100
|
+
|
101
|
+
%w[approximate_ascii scope strip_non_ascii use_slug].each do |method|
|
102
|
+
class_eval(<<-EOM)
|
103
|
+
def #{method}?
|
104
|
+
!! #{method}
|
105
|
+
end
|
106
|
+
EOM
|
107
|
+
end
|
108
|
+
|
109
|
+
alias :use_slugs? :use_slug?
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
|
3
|
+
module Finders
|
4
|
+
|
5
|
+
module Base
|
6
|
+
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :model_class, :base_class, :friendly_id_config,
|
10
|
+
:primary_key, :quoted_table_name, :sanitize_sql, :table_name
|
11
|
+
|
12
|
+
# Is the id friendly or numeric? Not that the return value here is
|
13
|
+
# +false+ if the +id+ is definitely not friendly, and +nil+ if it can
|
14
|
+
# not be determined.
|
15
|
+
# The return value will be:
|
16
|
+
# * +true+ - if the id is definitely friendly (i.e., any string with non-numeric characters)
|
17
|
+
# * +false+ - if the id is definitely unfriendly (i.e., an Integer, a model instance, etc.)
|
18
|
+
# * +nil+ - if it can not be determined (i.e., a numeric string like "206".)
|
19
|
+
# @return [true, false, nil]
|
20
|
+
# @see #unfriendly?
|
21
|
+
def self.friendly?(id)
|
22
|
+
if id.is_a?(Integer) or id.is_a?(Symbol) or id.class.respond_to? :friendly_id_config
|
23
|
+
return false
|
24
|
+
elsif id.to_i.to_s != id.to_s
|
25
|
+
return true
|
26
|
+
else
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Is the id numeric?
|
32
|
+
# @return [true, false, nil] +true+ if definitely unfriendly, +false+ if
|
33
|
+
# definitely friendly, else +nil+.
|
34
|
+
# @see #friendly?
|
35
|
+
def self.unfriendly?(id)
|
36
|
+
!friendly?(id) unless friendly?(id) == nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(ids, model_class, options={})
|
40
|
+
self.ids = ids
|
41
|
+
self.options = options
|
42
|
+
self.model_class = model_class
|
43
|
+
self.scope = options.delete :scope
|
44
|
+
end
|
45
|
+
|
46
|
+
# An array of ids; can be both friendly and unfriendly.
|
47
|
+
attr_accessor :ids
|
48
|
+
|
49
|
+
# The ActiveRecord query options
|
50
|
+
attr_accessor :options
|
51
|
+
|
52
|
+
# The FriendlyId scope
|
53
|
+
attr_accessor :scope
|
54
|
+
|
55
|
+
# The model class being used to perform the query.
|
56
|
+
attr_accessor :model_class
|
57
|
+
|
58
|
+
# Perform the find.
|
59
|
+
def find
|
60
|
+
raise NotImplementedError
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def ids=(ids)
|
66
|
+
@ids = [ids].flatten
|
67
|
+
end
|
68
|
+
alias :id= :ids=
|
69
|
+
|
70
|
+
def scope=(scope)
|
71
|
+
unless scope.nil?
|
72
|
+
@scope = scope.respond_to?(:to_param) ? scope.to_param : scope.to_s
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module Single
|
78
|
+
# Is the id definitely friendly?
|
79
|
+
# @see Finder::friendly?
|
80
|
+
def friendly?
|
81
|
+
Base.friendly?(id)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Is the id definitely unfriendly?
|
85
|
+
# @see Finder::unfriendly?
|
86
|
+
def unfriendly?
|
87
|
+
Base.unfriendly?(id)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# The id (numeric or friendly).
|
93
|
+
def id
|
94
|
+
ids[0]
|
95
|
+
end
|
96
|
+
|
97
|
+
# The slug name; i.e. if "my-title--2", then "my-title".
|
98
|
+
def name
|
99
|
+
id.to_s.parse_friendly_id(friendly_id_config.sequence_separator)[0]
|
100
|
+
end
|
101
|
+
|
102
|
+
# The slug sequence; i.e. if "my-title--2", then "2".
|
103
|
+
def sequence
|
104
|
+
id.to_s.parse_friendly_id(friendly_id_config.sequence_separator)[1]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|