friendly_id 3.0.4 → 3.0.5
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 +7 -0
- data/Guide.md +4 -2
- data/lib/friendly_id/active_record_adapter/slugged_model.rb +30 -20
- data/lib/friendly_id/active_record_adapter/tasks.rb +2 -2
- data/lib/friendly_id/slug_string.rb +4 -4
- data/lib/friendly_id/slugged.rb +1 -2
- data/lib/friendly_id/test.rb +22 -1
- data/lib/friendly_id/version.rb +1 -1
- data/test/active_record_adapter/ar_test_helper.rb +13 -1
- data/test/active_record_adapter/optimistic_locking_test.rb +18 -0
- data/test/active_record_adapter/slugged.rb +5 -0
- data/test/active_record_adapter/support/models.rb +8 -1
- data/test/slug_string_test.rb +1 -1
- data/test/test_helper.rb +2 -1
- metadata +10 -4
data/Changelog.md
CHANGED
@@ -6,6 +6,13 @@ suggestions, ideas and improvements to FriendlyId.
|
|
6
6
|
* Table of Contents
|
7
7
|
{:toc}
|
8
8
|
|
9
|
+
## 3.0.5 (2010-06-10)
|
10
|
+
|
11
|
+
* Fixed support for Rails 3.0 beta4 (Bruno Michel)
|
12
|
+
* Made rake tasks skip validations (Emilio Tagua).
|
13
|
+
* Fixed incorrect status of records found with a numeric friendly_id.
|
14
|
+
* Made slug an explicit has_one relation to enable eager-loading via :include => :slug
|
15
|
+
|
9
16
|
## 3.0.4 (2010-04-27)
|
10
17
|
|
11
18
|
* Fixed backwards-compatiblity with ActiveSupport 2.3.4 (Thanks Juergen Fesslmeier).
|
data/Guide.md
CHANGED
@@ -77,7 +77,7 @@ with Rails 2.2.x, 2.3.x. and 3.0.
|
|
77
77
|
After installing the gem, add an entry in environment.rb:
|
78
78
|
|
79
79
|
config.gem "friendly_id", :version => "~> 2.3"
|
80
|
-
|
80
|
+
|
81
81
|
### Rails 3.0
|
82
82
|
|
83
83
|
After installing the gem, add an entry in the Gemfile:
|
@@ -349,11 +349,13 @@ Checking the slugs table all the time has an impact on performance, so as of
|
|
349
349
|
### Automatic setup
|
350
350
|
|
351
351
|
To enable slug caching, simply add a column named "cached_slug" to your model.
|
352
|
+
Is also advised to index this column for performance reason.
|
352
353
|
FriendlyId will automatically use this column if it detects it:
|
353
354
|
|
354
355
|
class AddCachedSlugToUsers < ActiveRecord::Migration
|
355
356
|
def self.up
|
356
357
|
add_column :users, :cached_slug, :string
|
358
|
+
add_index :users, :cached_slug
|
357
359
|
end
|
358
360
|
|
359
361
|
def self.down
|
@@ -556,4 +558,4 @@ enabled. But if it is, then your patches would be very welcome!
|
|
556
558
|
find model using array of ids x1000 | 0.862 | 0.882 | 6.152 | 1.919 |
|
557
559
|
find model using id, then to_param x1000 | 0.658 | 2.200 | 8.398 | 1.539 |
|
558
560
|
================================================================================================
|
559
|
-
Total | 2.077 | 4.217 | 21.041 | 4.856 |
|
561
|
+
Total | 2.077 | 4.217 | 21.041 | 4.856 |
|
@@ -82,7 +82,7 @@ module FriendlyId
|
|
82
82
|
|
83
83
|
def find
|
84
84
|
@result = model_class.scoped(find_options).first(options)
|
85
|
-
handle_friendly_result if
|
85
|
+
handle_friendly_result if @result or friendly_id_config.scope?
|
86
86
|
@result
|
87
87
|
rescue ::ActiveRecord::RecordNotFound => @error
|
88
88
|
friendly_id_config.scope? ? raise_scoped_error : (raise @error)
|
@@ -120,9 +120,17 @@ module FriendlyId
|
|
120
120
|
|
121
121
|
def find
|
122
122
|
@result = model_class.scoped(find_options).first(options)
|
123
|
-
|
124
|
-
|
123
|
+
if @result
|
124
|
+
handle_friendly_result
|
125
|
+
@result
|
126
|
+
else
|
127
|
+
uncached_find
|
128
|
+
end
|
125
129
|
rescue ActiveRecord::RecordNotFound
|
130
|
+
uncached_find
|
131
|
+
end
|
132
|
+
|
133
|
+
def uncached_find
|
126
134
|
SingleFinder.new(id, model_class, options).find
|
127
135
|
end
|
128
136
|
|
@@ -136,7 +144,8 @@ module FriendlyId
|
|
136
144
|
def self.included(base)
|
137
145
|
base.class_eval do
|
138
146
|
has_many :slugs, :order => 'id DESC', :as => :sluggable, :dependent => :destroy
|
139
|
-
|
147
|
+
has_one :slug, :order => 'id DESC', :as => :sluggable, :dependent => :destroy
|
148
|
+
before_save :build_a_slug
|
140
149
|
after_save :set_slug_cache
|
141
150
|
after_update :update_scope
|
142
151
|
after_update :update_dependent_scopes
|
@@ -151,18 +160,6 @@ module FriendlyId
|
|
151
160
|
slugs.find_by_name_and_sequence(name, sequence)
|
152
161
|
end
|
153
162
|
|
154
|
-
# The model instance's current {FriendlyId::ActiveRecordAdapter::Slug slug}.
|
155
|
-
def slug
|
156
|
-
return @slug if new_record?
|
157
|
-
@slug ||= slugs.first(:order => "id DESC")
|
158
|
-
end
|
159
|
-
|
160
|
-
# Set the slug.
|
161
|
-
def slug=(slug)
|
162
|
-
@new_friendly_id = slug.to_friendly_id unless slug.nil?
|
163
|
-
super
|
164
|
-
end
|
165
|
-
|
166
163
|
# Returns the friendly id, or if none is available, the numeric id.
|
167
164
|
def to_param
|
168
165
|
friendly_id_config.cache_column ? to_param_from_cache : to_param_from_slug
|
@@ -185,9 +182,10 @@ module FriendlyId
|
|
185
182
|
end
|
186
183
|
|
187
184
|
# Build the new slug using the generated friendly id.
|
188
|
-
def
|
185
|
+
def build_a_slug
|
189
186
|
return unless new_slug_needed?
|
190
|
-
|
187
|
+
@slug = slugs.build :name => slug_text.to_s, :scope => friendly_id_config.scope_for(self)
|
188
|
+
@new_friendly_id = @slug.to_friendly_id
|
191
189
|
end
|
192
190
|
|
193
191
|
# Reset the cached friendly_id?
|
@@ -198,8 +196,13 @@ module FriendlyId
|
|
198
196
|
# Reset the cached friendly_id.
|
199
197
|
def set_slug_cache
|
200
198
|
if new_cache_needed?
|
201
|
-
|
202
|
-
|
199
|
+
begin
|
200
|
+
send "#{friendly_id_config.cache_column}=", slug.to_friendly_id
|
201
|
+
update_without_callbacks
|
202
|
+
rescue ActiveRecord::StaleObjectError
|
203
|
+
reload
|
204
|
+
retry
|
205
|
+
end
|
203
206
|
end
|
204
207
|
end
|
205
208
|
|
@@ -226,6 +229,13 @@ module FriendlyId
|
|
226
229
|
friendly_id_config.cache_column?
|
227
230
|
end
|
228
231
|
|
232
|
+
# This method was removed in ActiveRecord 3.0.
|
233
|
+
if !ActiveRecord::Base.private_method_defined? :update_without_callbacks
|
234
|
+
def update_without_callbacks
|
235
|
+
save :callbacks => false
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
229
239
|
end
|
230
240
|
end
|
231
241
|
end
|
@@ -31,7 +31,7 @@ module FriendlyId
|
|
31
31
|
while records = find(:all, options) do
|
32
32
|
break if records.size == 0
|
33
33
|
records.each do |record|
|
34
|
-
record.save
|
34
|
+
record.save(:validate => false)
|
35
35
|
yield(record) if block_given?
|
36
36
|
end
|
37
37
|
options[:conditions] = cond + " and #{klass.table_name}.id > #{records.last.id}"
|
@@ -66,4 +66,4 @@ module FriendlyId
|
|
66
66
|
|
67
67
|
end
|
68
68
|
|
69
|
-
end
|
69
|
+
end
|
@@ -191,7 +191,7 @@ module FriendlyId
|
|
191
191
|
# @param *args <Symbol>
|
192
192
|
# @return String
|
193
193
|
def approximate_ascii!(*args)
|
194
|
-
@maps = (self.class.approximations + args + [:common]).flatten.uniq
|
194
|
+
@maps = (self.class.approximations + args.flatten + [:common]).flatten.uniq
|
195
195
|
@wrapped_string = normalize_utf8(:c).unpack("U*").map { |char| approx_char(char) }.flatten.pack("U*")
|
196
196
|
end
|
197
197
|
|
@@ -206,7 +206,7 @@ module FriendlyId
|
|
206
206
|
# though your milage may vary with Greek and Turkic strings.
|
207
207
|
# @return String
|
208
208
|
def downcase!
|
209
|
-
@wrapped_string = apply_mapping :lowercase_mapping
|
209
|
+
@wrapped_string = ActiveSupport::Multibyte::Unicode.apply_mapping(@wrapped_string, :lowercase_mapping)
|
210
210
|
end
|
211
211
|
|
212
212
|
# Remove any non-word characters.
|
@@ -235,7 +235,7 @@ module FriendlyId
|
|
235
235
|
# @param config [FriendlyId::Configuration]
|
236
236
|
# @return String
|
237
237
|
def normalize_for!(config)
|
238
|
-
approximate_ascii! if config.approximate_ascii?
|
238
|
+
approximate_ascii!(config.ascii_approximation_options) if config.approximate_ascii?
|
239
239
|
to_ascii! if config.strip_non_ascii?
|
240
240
|
normalize!
|
241
241
|
end
|
@@ -333,7 +333,7 @@ module FriendlyId
|
|
333
333
|
# though your milage may vary with Greek and Turkic strings.
|
334
334
|
# @return String
|
335
335
|
def upcase!
|
336
|
-
@wrapped_string = apply_mapping :uppercase_mapping
|
336
|
+
@wrapped_string = ActiveSupport::Multibyte::Unicode.apply_mapping(@wrapped_string, :uppercase_mapping)
|
337
337
|
end
|
338
338
|
|
339
339
|
# Validate that the slug string is not blank or reserved, and truncate
|
data/lib/friendly_id/slugged.rb
CHANGED
data/lib/friendly_id/test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
Module.send :include, Module.new {
|
2
3
|
def test(name, &block)
|
3
4
|
define_method("test_#{name.gsub(/[^a-z0-9]/i, "_")}".to_sym, &block)
|
@@ -141,7 +142,7 @@ module FriendlyId
|
|
141
142
|
test "should make a new slug if the friendly_id method value has changed" do
|
142
143
|
instance.name = "Changed title"
|
143
144
|
instance.send save_method
|
144
|
-
assert_equal 2, instance.slugs.size
|
145
|
+
assert_equal 2, instance.slugs(true).size
|
145
146
|
end
|
146
147
|
|
147
148
|
test "should be able to reuse an old friendly_id without incrementing the sequence" do
|
@@ -170,6 +171,13 @@ module FriendlyId
|
|
170
171
|
assert instance2.friendly_id_status.best?
|
171
172
|
end
|
172
173
|
|
174
|
+
test "should indicate correct status when found by a numeric friendly_id" do
|
175
|
+
instance = klass.send(create_method, :name => "100")
|
176
|
+
instance2 = klass.send(find_method, "100")
|
177
|
+
assert instance2.friendly_id_status.best?, "status expected to be best but isn't."
|
178
|
+
assert instance2.friendly_id_status.current?, "status expected to be current but isn't."
|
179
|
+
end
|
180
|
+
|
173
181
|
test "should remain findable by previous slugs" do
|
174
182
|
old_friendly_id = instance.friendly_id
|
175
183
|
instance.name = "#{old_friendly_id} updated"
|
@@ -194,6 +202,19 @@ module FriendlyId
|
|
194
202
|
end
|
195
203
|
end
|
196
204
|
|
205
|
+
test "should approximate ascii if configured" do
|
206
|
+
klass.friendly_id_config.stubs(:approximate_ascii?).returns(true)
|
207
|
+
instance = klass.send(create_method, :name => "Cañón")
|
208
|
+
assert_equal "canon", instance.friendly_id
|
209
|
+
end
|
210
|
+
|
211
|
+
test "should approximate ascii with options if configured" do
|
212
|
+
klass.friendly_id_config.stubs(:approximate_ascii?).returns(true)
|
213
|
+
klass.friendly_id_config.stubs(:ascii_approximation_options).returns(:spanish)
|
214
|
+
instance = klass.send(create_method, :name => "Cañón")
|
215
|
+
assert_equal "cannon", instance.friendly_id
|
216
|
+
end
|
217
|
+
|
197
218
|
end
|
198
219
|
|
199
220
|
# Tests for FriendlyId::Status.
|
data/lib/friendly_id/version.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require File.expand_path('../../test_helper', __FILE__)
|
2
2
|
|
3
|
+
require "logger"
|
3
4
|
require "active_record"
|
4
5
|
require "active_support"
|
5
6
|
|
7
|
+
# ActiveRecord::Base.logger = Logger.new($stdout)
|
8
|
+
|
6
9
|
require File.expand_path("../../../lib/friendly_id/active_record", __FILE__)
|
7
10
|
require File.expand_path("../../../generators/friendly_id/templates/create_slugs", __FILE__)
|
8
11
|
require File.expand_path("../support/models", __FILE__)
|
@@ -31,6 +34,15 @@ class District < ActiveRecord::Base
|
|
31
34
|
has_friendly_id :name, :use_slug => true
|
32
35
|
end
|
33
36
|
|
37
|
+
# A model with optimistic locking enabled
|
38
|
+
class Region < ActiveRecord::Base
|
39
|
+
has_friendly_id :name, :use_slug => true
|
40
|
+
after_create do |obj|
|
41
|
+
other_instance = self.class.find obj.id
|
42
|
+
other_instance.update_attributes :note => name + "!"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
34
46
|
# A model that specifies a custom cached slug column
|
35
47
|
class City < ActiveRecord::Base
|
36
48
|
has_friendly_id :name, :use_slug => true, :cache_column => "my_slug"
|
@@ -116,4 +128,4 @@ end
|
|
116
128
|
# A model used as a polymorphic owner
|
117
129
|
class Company < ActiveRecord::Base
|
118
130
|
has_many :sites, :as => :owner
|
119
|
-
end
|
131
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path("../ar_test_helper", __FILE__)
|
2
|
+
|
3
|
+
module FriendlyId
|
4
|
+
module Test
|
5
|
+
module ActiveRecordAdapter
|
6
|
+
class OptimisticLockingTest < ::Test::Unit::TestCase
|
7
|
+
test "should update the cached slug when updating the slug" do
|
8
|
+
region = Region.create! :name => 'some name'
|
9
|
+
assert_nothing_raised do
|
10
|
+
region.update_attributes(:name => "new name")
|
11
|
+
end
|
12
|
+
assert_equal region.slug.to_friendly_id, region.cached_slug
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -23,6 +23,13 @@ class CreateSupportModels < ActiveRecord::Migration
|
|
23
23
|
end
|
24
24
|
add_index :cities, :my_slug, :unique => true
|
25
25
|
|
26
|
+
create_table :regions do |t|
|
27
|
+
t.string :name
|
28
|
+
t.string :cached_slug
|
29
|
+
t.string :note
|
30
|
+
t.integer :lock_version, :null => false, :default => 0
|
31
|
+
end
|
32
|
+
add_index :regions, :cached_slug, :unique => true
|
26
33
|
|
27
34
|
create_table :countries do |t|
|
28
35
|
t.string :name
|
@@ -76,7 +83,7 @@ class CreateSupportModels < ActiveRecord::Migration
|
|
76
83
|
t.integer :owner_id
|
77
84
|
t.string :owner_type
|
78
85
|
end
|
79
|
-
|
86
|
+
|
80
87
|
create_table :companies do |t|
|
81
88
|
t.string :name
|
82
89
|
end
|
data/test/slug_string_test.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -11,5 +11,6 @@ end
|
|
11
11
|
require "test/unit"
|
12
12
|
require "mocha"
|
13
13
|
require "active_support"
|
14
|
+
require "ruby-debug"
|
14
15
|
require File.expand_path("../../lib/friendly_id", __FILE__)
|
15
|
-
require File.expand_path("../../lib/friendly_id/test", __FILE__)
|
16
|
+
require File.expand_path("../../lib/friendly_id/test", __FILE__)
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 3
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 3.0.
|
8
|
+
- 5
|
9
|
+
version: 3.0.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Norman Clarke
|
@@ -16,13 +16,14 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-
|
19
|
+
date: 2010-06-10 00:00:00 -04:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
23
23
|
name: activerecord
|
24
24
|
prerelease: false
|
25
25
|
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
26
27
|
requirements:
|
27
28
|
- - ">="
|
28
29
|
- !ruby/object:Gem::Version
|
@@ -36,6 +37,7 @@ dependencies:
|
|
36
37
|
name: activesupport
|
37
38
|
prerelease: false
|
38
39
|
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
39
41
|
requirements:
|
40
42
|
- - ">="
|
41
43
|
- !ruby/object:Gem::Version
|
@@ -91,6 +93,7 @@ files:
|
|
91
93
|
- test/active_record_adapter/core.rb
|
92
94
|
- test/active_record_adapter/custom_normalizer_test.rb
|
93
95
|
- test/active_record_adapter/custom_table_name_test.rb
|
96
|
+
- test/active_record_adapter/optimistic_locking_test.rb
|
94
97
|
- test/active_record_adapter/scoped_model_test.rb
|
95
98
|
- test/active_record_adapter/simple_test.rb
|
96
99
|
- test/active_record_adapter/slug_test.rb
|
@@ -122,6 +125,7 @@ rdoc_options: []
|
|
122
125
|
require_paths:
|
123
126
|
- lib
|
124
127
|
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
125
129
|
requirements:
|
126
130
|
- - ">="
|
127
131
|
- !ruby/object:Gem::Version
|
@@ -129,6 +133,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
133
|
- 0
|
130
134
|
version: "0"
|
131
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
132
137
|
requirements:
|
133
138
|
- - ">="
|
134
139
|
- !ruby/object:Gem::Version
|
@@ -138,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
143
|
requirements: []
|
139
144
|
|
140
145
|
rubyforge_project: friendly-id
|
141
|
-
rubygems_version: 1.3.
|
146
|
+
rubygems_version: 1.3.7
|
142
147
|
signing_key:
|
143
148
|
specification_version: 3
|
144
149
|
summary: A comprehensive slugging and pretty-URL plugin.
|
@@ -147,6 +152,7 @@ test_files:
|
|
147
152
|
- test/active_record_adapter/cached_slug_test.rb
|
148
153
|
- test/active_record_adapter/custom_normalizer_test.rb
|
149
154
|
- test/active_record_adapter/custom_table_name_test.rb
|
155
|
+
- test/active_record_adapter/optimistic_locking_test.rb
|
150
156
|
- test/active_record_adapter/scoped_model_test.rb
|
151
157
|
- test/active_record_adapter/simple_test.rb
|
152
158
|
- test/active_record_adapter/slug_test.rb
|