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 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 friendly?
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
- handle_friendly_result if friendly?
124
- @result
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
- before_save :build_slug
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 build_slug
185
+ def build_a_slug
189
186
  return unless new_slug_needed?
190
- self.slug = slugs.build :name => slug_text.to_s, :scope => friendly_id_config.scope_for(self)
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
- send "#{friendly_id_config.cache_column}=", slug.to_friendly_id
202
- send :update_without_callbacks
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
@@ -96,7 +96,6 @@ module FriendlyId
96
96
  !slug? || slug_text_changed?
97
97
  end
98
98
  end
99
-
100
99
  end
101
100
  end
102
- end
101
+ end
@@ -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.
@@ -2,7 +2,7 @@ module FriendlyId
2
2
  module Version
3
3
  MAJOR = 3
4
4
  MINOR = 0
5
- TINY = 4
5
+ TINY = 5
6
6
  BUILD = nil
7
7
  STRING = [MAJOR, MINOR, TINY, BUILD].compact.join('.')
8
8
  end
@@ -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
+
@@ -9,6 +9,11 @@ module FriendlyId
9
9
  assert_nothing_raised do
10
10
  klass.find(instance.friendly_id, :include => :slugs)
11
11
  end
12
+
13
+ assert_nothing_raised do
14
+ klass.find(instance.friendly_id, :include => :slug)
15
+ end
16
+
12
17
  end
13
18
 
14
19
  def klass
@@ -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
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- require(File.dirname(__FILE__) + "/test_helper")
2
+ require(File.expand_path("../test_helper", __FILE__))
3
3
 
4
4
  module FriendlyId
5
5
  module Test
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
- - 4
9
- version: 3.0.4
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-04-27 00:00:00 -03:00
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.6
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