friendly_id 3.0.4 → 3.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|