dougcole-friendly_id 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/History.txt +88 -0
  2. data/MIT-LICENSE +19 -0
  3. data/Manifest.txt +45 -0
  4. data/README.rdoc +318 -0
  5. data/Rakefile +67 -0
  6. data/generators/friendly_id/friendly_id_generator.rb +12 -0
  7. data/generators/friendly_id/templates/create_slugs.rb +18 -0
  8. data/generators/friendly_id_20_upgrade/friendly_id_20_upgrade_generator.rb +11 -0
  9. data/generators/friendly_id_20_upgrade/templates/upgrade_friendly_id_to_20.rb +19 -0
  10. data/init.rb +1 -0
  11. data/lib/friendly_id/helpers.rb +13 -0
  12. data/lib/friendly_id/non_sluggable_class_methods.rb +40 -0
  13. data/lib/friendly_id/non_sluggable_instance_methods.rb +33 -0
  14. data/lib/friendly_id/shoulda_macros.rb +36 -0
  15. data/lib/friendly_id/slug.rb +89 -0
  16. data/lib/friendly_id/sluggable_class_methods.rb +103 -0
  17. data/lib/friendly_id/sluggable_instance_methods.rb +106 -0
  18. data/lib/friendly_id/version.rb +8 -0
  19. data/lib/friendly_id.rb +67 -0
  20. data/lib/tasks/friendly_id.rake +48 -0
  21. data/lib/tasks/friendly_id.rb +1 -0
  22. data/test/database.yml +3 -0
  23. data/test/fixtures/countries.yml +4 -0
  24. data/test/fixtures/country.rb +4 -0
  25. data/test/fixtures/people.yml +7 -0
  26. data/test/fixtures/person.rb +6 -0
  27. data/test/fixtures/post.rb +3 -0
  28. data/test/fixtures/posts.yml +23 -0
  29. data/test/fixtures/slugs.yml +53 -0
  30. data/test/fixtures/user.rb +3 -0
  31. data/test/fixtures/users.yml +7 -0
  32. data/test/non_slugged_test.rb +85 -0
  33. data/test/rails/2.x/app/controllers/application.rb +0 -0
  34. data/test/rails/2.x/config/boot.rb +109 -0
  35. data/test/rails/2.x/config/database.yml +3 -0
  36. data/test/rails/2.x/config/environment.rb +7 -0
  37. data/test/rails/2.x/config/environments/test.rb +6 -0
  38. data/test/rails/2.x/config/routes.rb +0 -0
  39. data/test/schema.rb +38 -0
  40. data/test/scoped_model_test.rb +21 -0
  41. data/test/slug_test.rb +87 -0
  42. data/test/sluggable_test.rb +185 -0
  43. data/test/test_helper.rb +35 -0
  44. metadata +157 -0
data/History.txt ADDED
@@ -0,0 +1,88 @@
1
+ == 2.0.1 2009-01-19
2
+
3
+ * 1 minor enhancements:
4
+ * Fix infinite redirect bug when using .has_better_id? in your controllers (Sean Abrahams)
5
+
6
+
7
+ == 2.0.0 2009-01-03
8
+
9
+ * 5 major enhancements:
10
+ * Support for scoped slugs (Norman Clarke)
11
+ * Support for UTF-8 friendly_ids (Norman Clarke)
12
+ * Can now be installed via Ruby Gems, or as a Rails plugin (Norman Clarke)
13
+ * Improved handling of non-unique slugs (Norman Clarke and Adrian Mugnolo)
14
+ * 2 minor enhancements:
15
+ * Shoulda macro (Josh Nichols)
16
+ * Various small bugfixes, cleanups and refactorings
17
+
18
+ == 2008-12-01
19
+
20
+ * Fixed bug that may return invalid records having similar id/names and using MySQL. (Emilio Tagua)
21
+ * Fixed slug generation to increment only numeric extension without modifying the name on duplicated slugs. (Emilio Tagua)
22
+
23
+ == 2008-10-31
24
+
25
+ * Fixed compatibility with Rails 2.0.x. (Norman Clarke)
26
+ * friendly_id::make_slugs update records in chunks of 1000 to avoid running out of memory with large datasets. (Tim Kadom)
27
+ * Fixed logic error with slug name collisions. Thanks to Tim Kadom for reporting this bug.
28
+
29
+ == 2008-10-22
30
+
31
+ * Reverted use of UTF8Handler - was causing errors for some people (Bence Nagy)
32
+ * Corrected find in case if a friendly_id begins with number (Bence Nagy)
33
+ * Added ability to reserve words from slugs (Adam Cigánek)
34
+
35
+ == 2008-10-09
36
+
37
+ * Moved "require"" for iconv to init.rb (Florian Aßmann)
38
+ * Removed "require" for Unicode, use Rails' handler instead (Florian Aßmann)
39
+ * Replaced some magic numbers with constants (Florian Aßmann)
40
+ * Don't overwrite find, alias_method_chain find_one and find_some instead (Florian Aßmann)
41
+ * Slugs behave more like ids now (Florian Aßmann)
42
+ * Can find by mixture of ids and slugs (Florian Aßmann)
43
+ * Reformatted code and comments (Florian Aßmann)
44
+ * Added support for Edge Rails' Inflector::parameterize (Norman Clarke)
45
+
46
+ == 2008-08-25
47
+
48
+ * Moved strip_diacritics into Slug for easier reuse/better organization.
49
+ * Put class methods inside class << self block. (Norman Clarke)
50
+
51
+ * Small change to allow friendly_id to work better with STI. (David Ramalho)
52
+
53
+ == 2008-07-14
54
+
55
+ * Improved slug generation for friendly id's with apostrophes. (alistairholt)
56
+ * Added support for namespaced models in Rakefile. (David Ramalho)
57
+
58
+ == 2008-06-23
59
+
60
+ * Cached most recent slug to improve performance (Emilio Tagua).
61
+
62
+ == 2008-06-10
63
+
64
+ * Added ability to find friendly_ids by array (Emilio Tagua)
65
+
66
+ == 2008-05-15
67
+
68
+ * Made friendly_id raise an error if slug method returns a blank value.
69
+
70
+ == 2008-05-12
71
+
72
+ * Added experimental Github gemspec.
73
+
74
+ == 2008-04-18
75
+
76
+ * Improved slug name collision avoidance.
77
+
78
+ == 2008-03-13
79
+
80
+ * Added :dependent => :destroy to slug relation, as suggested by Emilio Tagua.
81
+ * Fixed error when renaming a slugged item back to a previously used name.
82
+ * Incorporated documentation changes suggested by Jesse Crouch and Chris Nolan.
83
+
84
+ == 2008-02-07
85
+
86
+ * Applied patches from blog commenter "suntzu" to fix problem with model values were being overwritten.
87
+ * Applied patch from Dan Blue to make friendly_id no longer ignore options on ActiveRecordBase#find.
88
+ * Added call to options.assert_valid_keys in has_friendly_id. Thanks to W. Andrew Loe III for pointing out that this was missing.
data/MIT-LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 Norman Clarke and Adrian Mugnolo.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,45 @@
1
+ History.txt
2
+ MIT-LICENSE
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ config/website.yml
7
+ friendly_id.gemspec
8
+ generators/friendly_id/friendly_id_generator.rb
9
+ generators/friendly_id/templates/create_slugs.rb
10
+ generators/friendly_id_20_upgrade/friendly_id_20_upgrade_generator.rb
11
+ generators/friendly_id_20_upgrade/templates/upgrade_friendly_id_to_20.rb
12
+ init.rb
13
+ lib/friendly_id.rb
14
+ lib/friendly_id/helpers.rb
15
+ lib/friendly_id/non_sluggable_class_methods.rb
16
+ lib/friendly_id/non_sluggable_instance_methods.rb
17
+ lib/friendly_id/shoulda_macros.rb
18
+ lib/friendly_id/slug.rb
19
+ lib/friendly_id/sluggable_class_methods.rb
20
+ lib/friendly_id/sluggable_instance_methods.rb
21
+ lib/friendly_id/version.rb
22
+ lib/tasks/friendly_id.rake
23
+ lib/tasks/friendly_id.rb
24
+ test/database.yml
25
+ test/fixtures/countries.yml
26
+ test/fixtures/country.rb
27
+ test/fixtures/people.yml
28
+ test/fixtures/person.rb
29
+ test/fixtures/post.rb
30
+ test/fixtures/posts.yml
31
+ test/fixtures/slugs.yml
32
+ test/fixtures/user.rb
33
+ test/fixtures/users.yml
34
+ test/non_slugged_test.rb
35
+ test/rails/2.x/app/controllers/application.rb
36
+ test/rails/2.x/config/boot.rb
37
+ test/rails/2.x/config/database.yml
38
+ test/rails/2.x/config/environment.rb
39
+ test/rails/2.x/config/environments/test.rb
40
+ test/rails/2.x/config/routes.rb
41
+ test/schema.rb
42
+ test/scoped_model_test.rb
43
+ test/slug_test.rb
44
+ test/sluggable_test.rb
45
+ test/test_helper.rb
data/README.rdoc ADDED
@@ -0,0 +1,318 @@
1
+ = FriendlyId
2
+
3
+ FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for
4
+ Ruby on Rails. It allows you to create pretty URL's and work with
5
+ human-friendly strings as if they were numeric ids for ActiveRecord models.
6
+
7
+ Using FriendlyId, it's easy to make your application use URL's like:
8
+
9
+ http://example.com/states/washington
10
+
11
+ instead of:
12
+
13
+ http://example.com/states/4323454
14
+
15
+ Want to find out more? Read on. The {most recent version of the FriendlyId
16
+ RDocs}[http://friendly-id.rubyforge.org] can always be found on
17
+ Rubyforge[http://www.rubyforge.org].
18
+
19
+ === Why?
20
+
21
+ * Text-based id's look better
22
+ * They make URL's easier to remember.
23
+ * They give no hint about the number of records in your database.
24
+ * They are better for search engine optimization.
25
+
26
+ === But...
27
+
28
+ * They can change, breaking your URL's and your SEO.
29
+ * It can be tricky to ensure they're always unique.
30
+ * They can become a pain to manage in large Rails applications.
31
+ * They can conflict with your application's namespace.
32
+
33
+ FriendlyId tries to offer you the all the advantages, and avoid or soften the
34
+ potential impact of the disadvantages.
35
+
36
+ == Typical Uses
37
+
38
+ === User names ("non-slugged" models)
39
+
40
+ Usually users have unique user names stored in a column with a unique
41
+ constraint or index. In this case, all you need to do is add this to your
42
+ model:
43
+
44
+ has_friendly_id :login
45
+
46
+ and you can then write code like this:
47
+
48
+ @member = Member.find("joe") # the old Member.find(1) still works, too.
49
+ @member.to_param # returns "joe"
50
+ redirect_to @member # The URL would be /members/joe
51
+
52
+ === Blog posts ("slugged" models)
53
+
54
+ Blog posts generally have titles which are distinctive but not necessarily
55
+ unique. In this and similar cases, FriendlyId provides a Slug model separate
56
+ from your Post model. The Slug model handles duplicate friendly_ids, as well
57
+ as versioning.
58
+
59
+ Your model code would look something like this:
60
+
61
+ has_friendly_id :title, :use_slug => true
62
+
63
+ and you can then write code like this:
64
+
65
+ @post = Post.find("new-version-released") # Post.find(1) still works, too
66
+ @post.to_param # returns "new-version-released"
67
+ redirect_to @post # The URL would be /posts/new-version-released
68
+
69
+ Now in your controllers, if you want to prevent people from accessing your
70
+ models by numeric id, you can detect whether they were found by the
71
+ friendly_id:
72
+
73
+ @post = Post.find(params[:id])
74
+ raise "some error" if !@post.found_using_friendly_id?
75
+
76
+ or, you can 301 redirect if the model was found by the numeric id if you don't
77
+ care about numeric access, but want the SEO value of the friendly_id:
78
+
79
+ @post = Post.find(params[:id])
80
+ redirect_to @post, :status => 301 if @post.has_better_id?
81
+
82
+ The "has_better_id?" method returns true if the model was found with the
83
+ numeric id, or with an outdated slug.
84
+
85
+ == Extra Features
86
+
87
+ === Slug Versioning
88
+
89
+ FriendlyId will record changes to slugs so that you can tell when the model is
90
+ found with an older slug, or by the numeric id. This can be useful if you want
91
+ to do a 301 redirect to your updated URL.
92
+
93
+ class PostsController < ApplicationController
94
+
95
+ before_filter ensure_current_post_url, :only => :show
96
+
97
+ ...
98
+
99
+ def ensure_current_post_url
100
+ redirect_to @post, :status => :moved_permanently if @post.has_better_id?
101
+ end
102
+
103
+ end
104
+
105
+ This is particularly useful when implementing FrindlyId on an existing
106
+ website that already has many URL's with the old numeric id listed on search
107
+ engines. When the search engine spiders crawl your site, they will
108
+ eventually pick up the new, more SEO-friendly URL's.
109
+
110
+ === Non-unique Slug Names
111
+
112
+ FriendlyId will append a arbitrary number to the end of the id to keep it
113
+ unique if necessary:
114
+
115
+ /posts/new-version-released
116
+ /posts/new-version-released--2
117
+ /posts/new-version-released--3
118
+ ...
119
+ etc.
120
+
121
+ Note that the number is preceeded by two dashes to distinguish it from the
122
+ rest of the slug. This is important to enable having slugs like:
123
+
124
+ /cars/peugeot-206
125
+ /cars/peugeot-206--2
126
+
127
+ === Reserved Names
128
+
129
+ You can mark off some strings as reserved so that, for example, you don't end
130
+ up with this problem:
131
+
132
+ /users/joe-schmoe # A user chose "joe schmoe" as his user name - no worries.
133
+ /users/new # A user chose "new" as his user name, and now no one can sign up.
134
+
135
+ Here's how to do it:
136
+
137
+ class Restaurant < ActiveRecord::Base
138
+ belongs_to :city
139
+ has_friendly_id :name, :use_slug => true, :reserved => ["new", "index"]
140
+ end
141
+
142
+
143
+ === Scoped Slugs
144
+
145
+ FriendlyId can generate unique slugs within a given scope. For example:
146
+
147
+ class Restaurant < ActiveRecord::Base
148
+ belongs_to :city
149
+ has_friendly_id :name, :use_slug => true, :scope => :city
150
+ end
151
+
152
+ class City < ActiveRecord::Base
153
+ has_many :restaurants
154
+ has_friendly_id :name, :use_slug => true
155
+ end
156
+
157
+ http://example.org/cities/seattle/restaurants/joes-diner
158
+ http://example.org/cities/chicago/restaurants/joes-diner
159
+
160
+ Restaurant.find("joes-diner", :scope => "seattle") # returns 1 record
161
+ Restaurant.find("joes-diner", :scope => "chicago") # returns 1 record
162
+ Restaurant.find("joes-diner") # returns both records
163
+
164
+
165
+ The value for the :scope key in your model can be a custom method you define,
166
+ or the name of a relation. If it's the name of a relation, then the scope's
167
+ text value will be the result of calling <code>to_param</code> on the related
168
+ model record. In the example above, the city model also uses FriendlyId and so
169
+ its <code>to_param</code> method returns its friendly_id: chicago or seattle.
170
+
171
+ This feature is new in FriendlyId 2 and should be considered of experimental
172
+ quality. Please don't use this for code that needs to run on the Space
173
+ Shuttle.
174
+
175
+ === Text Normalization
176
+
177
+ FriendlyId's slugging can strip diacritics from Western European characters,
178
+ so that you can have ASCII-only URL's; for example, conveting "ñøîéçü" to
179
+ "noiecu."
180
+
181
+ has_friendly_id :title, :use_slug => true, :strip_diacritics => true
182
+
183
+ If you are not using slugs, you'll have to do this manually for whatever value
184
+ you're using as the friendly_id.
185
+
186
+ === Diacritic-sensitive normalization
187
+
188
+ FriendlyId can also normalize slug text while preserving accented characters, if
189
+ you prefer to leave them in your URL's:
190
+
191
+ has_friendly_id :title, :use_slug => true
192
+ ...
193
+ @post = Post.create(:title => "¡Feliz Año!")
194
+ @post.friendly_id # "feliz-año"
195
+
196
+ === Unicode URL's
197
+
198
+ FriendlyId can generate slugs in any language that can be written with
199
+ Unicode. It does its best to strip away punctuation regardless of the language
200
+ being used. Since the authors only speak English, Spanish, Portuguese and
201
+ German, this has not been extensively tested with anything like Chinese,
202
+ Russian, Greek, etc, but it "should work." If you're a speaker of a language
203
+ that uses a non-Roman writing system, your feedback would be most welcome.
204
+
205
+ has_friendly_id :title, :use_slug => true
206
+ ...
207
+ @post = Post.create(:title => "友好编号在中国")
208
+ @post.friendly_id # "友好编号在中国"
209
+ @post2 = Post.create(:title => "友好编号在中国")
210
+ @post2.friendly_id # "友好编号在中国--2"
211
+
212
+ == Getting it
213
+
214
+ FriendlyId is installed as a Ruby Gem:
215
+
216
+ gem install friendly_id
217
+
218
+ Alternatively, you can install it as a Rails plugin, though this is
219
+ discouraged:
220
+
221
+ ./script/plugin install git://github.com/norman/friendly_id.git
222
+
223
+ If you are installing as a plugin, make sure you have installed the unicode gem,
224
+ which FriendlyId depends on:
225
+
226
+ gem install unicode
227
+
228
+
229
+ == Setting it up
230
+
231
+ FriendlyId currently works with Rails 2.0.0 and higher. Here's how to set it up.
232
+
233
+ 1) Install the Gem:
234
+
235
+ sudo gem install friendly_id
236
+ cd my_app
237
+ script/generate friendly_id
238
+ rake db:migrate
239
+
240
+ 2) Load FriendlyId in your app:
241
+
242
+ # Rails 2.1 and higher; add this to the gem section of environment.rb:
243
+ config.gem "friendly_id"
244
+
245
+ # Rails 2.0; this goes at the bottom of environment.rb
246
+ require 'friendly_id'
247
+
248
+ 3) Add some code to your models:
249
+
250
+ class Post < ActiveRecord::Base
251
+ has_friendly_id :title, :use_slug => true
252
+ end
253
+
254
+ 4) If you are using slugs, you can use a Rake task to generate slugs for your
255
+ existing records:
256
+
257
+ friendly_id:make_slugs MODEL=MyModelName
258
+
259
+ If you eventually want to expire old slugs every so often, or perhaps every
260
+ day via cron, you can do:
261
+
262
+ rake:friendly_id:remove_old_slugs
263
+
264
+ The default is to remove dead slugs older than 45 days, but is configurable:
265
+
266
+ rake:friendly_id:remove_old_slugs MODEL=MyModelName DAYS=60
267
+
268
+ == Upgrading from an older version
269
+
270
+ If you installed an older version of FriendlyId and want to upgrade to 2.0,
271
+ follow these steps:
272
+
273
+ ==== Install the friendly_id Gem:
274
+
275
+ sudo gem install friendly_id
276
+
277
+ ==== Add FriendlyId to environment.rb:
278
+
279
+ ===== For Rails 2.1 and higher:
280
+
281
+ config.gem "friendly_id"
282
+
283
+ ===== For Rails 2.0:
284
+
285
+ Add this to the bottom of environment.rb:
286
+
287
+ require 'friendly_id'
288
+
289
+ ==== Remove the older version of FriendlyId:
290
+
291
+ git rm -rf vendor/plugins/friendly_id
292
+ svn delete vendor/plugins/friendly_id
293
+ # or whatever
294
+
295
+ ==== Generate the upgrade migration and run it
296
+
297
+ ./script generate friendly_id_20_upgrade
298
+ rake db:migrate
299
+
300
+ That's it!
301
+
302
+ == Hacking FriendlyId:
303
+
304
+ FriendlyId is {hosted on Github}[git://github.com/norman/friendly_id.git], and
305
+ we love pull requests. :-)
306
+
307
+ == Bugs:
308
+
309
+ Please report them on Lighthouse[http://randomba.lighthouseapp.com/projects/14675-friendly_id].
310
+
311
+
312
+ == Credits:
313
+
314
+ FriendlyId was created by {Norman Clarke}[mailto:norman@randomba.org],
315
+ {Adrian Mugnolo}[mailto:adrian@randomba.org], and {Emilio Tagua}[mailto:miloops@gmail.com].
316
+
317
+ Copyright (c) 2008 Norman Clarke, Adrian Mugnolo and Emilio Tagua, released
318
+ under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,67 @@
1
+ require 'rubygems'
2
+ require 'lib/friendly_id/version'
3
+ require 'rake/gempackagetask'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |s|
8
+ s.name = "friendly_id"
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.authors = ["Norman Clarke", "Adrian Mugnolo", "Emilio Tagua"]
11
+ s.summary = %q{A comprehensive slugging and pretty-URL plugin for Ruby on Rails.}
12
+ s.email = ["norman@randomba.org", "adrian@randomba.org", "miloops@gmail.com"]
13
+ s.homepage = %q{http://randomba.org}
14
+ s.description = %q{A comprehensive slugging and pretty-URL plugin for Ruby on Rails.}
15
+ s.add_dependency 'schacon-git'
16
+ s.has_rdoc = true
17
+ s.rdoc_options = ["--main", "README.rdoc"]
18
+ s.require_paths = ["lib"]
19
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
20
+ s.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*","init.rb"]
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 2
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ s.add_runtime_dependency(%q<unicode>, [">= 0.1"])
27
+ s.add_development_dependency(%q<newgem>, [">= 1.2.3"])
28
+ s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
29
+ else
30
+ s.add_dependency(%q<unicode>, [">= 0.1"])
31
+ s.add_dependency(%q<newgem>, [">= 1.2.3"])
32
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
33
+ end
34
+ else
35
+ s.add_dependency(%q<unicode>, [">= 0.1"])
36
+ s.add_dependency(%q<newgem>, [">= 1.2.3"])
37
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
38
+ end
39
+ end
40
+ rescue LoadError
41
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
42
+ end
43
+
44
+
45
+ desc "Run RCov"
46
+ task :rcov do
47
+ run_coverage Dir["test/**/*_test.rb"]
48
+ end
49
+
50
+ def run_coverage(files)
51
+ rm_f "coverage"
52
+ rm_f "coverage.data"
53
+ if files.length == 0
54
+ puts "No files were specified for testing"
55
+ return
56
+ end
57
+ files = files.join(" ")
58
+ if PLATFORM =~ /darwin/
59
+ exclude = '--exclude "gems/"'
60
+ else
61
+ exclude = '--exclude "rubygems"'
62
+ end
63
+ rcov = "rcov -Ilib:test --sort coverage --text-report #{exclude} --no-validator-links"
64
+ cmd = "#{rcov} #{files}"
65
+ puts cmd
66
+ sh cmd
67
+ end
@@ -0,0 +1,12 @@
1
+ class FriendlyIdGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ unless options[:skip_migration]
5
+ m.migration_template(
6
+ 'create_slugs.rb', 'db/migrate', :migration_file_name => 'create_slugs'
7
+ )
8
+ m.file "/../../../lib/tasks/friendly_id.rake", "lib/tasks/friendly_id.rake"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ class CreateSlugs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :slugs do |t|
4
+ t.string :name
5
+ t.integer :sluggable_id
6
+ t.integer :sequence, :null => false, :default => 1
7
+ t.string :sluggable_type, :limit => 40
8
+ t.string :scope, :limit => 40
9
+ t.datetime :created_at
10
+ end
11
+ add_index :slugs, [:name, :sluggable_type, :scope, :sequence], :unique => true
12
+ add_index :slugs, :sluggable_id
13
+ end
14
+
15
+ def self.down
16
+ drop_table :slugs
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ class FriendlyId20UpgradeGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ unless options[:skip_migration]
5
+ m.migration_template(
6
+ 'upgrade_friendly_id_to_20.rb', 'db/migrate', :migration_file_name => 'upgrade_friendly_id_to_20'
7
+ )
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ class UpgradeFriendlyIdTo20 < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ remove_column :slugs, :updated_at
5
+ remove_index :slugs, :column => [:name, :sluggable_type]
6
+ add_column :slugs, :sequence, :integer, :null => false, :default => 1
7
+ add_column :slugs, :scope, :string, :limit => 40
8
+ add_index :slugs, [:name, :sluggable_type, :scope, :sequence], :unique => true, :name => "index_slugs_on_n_s_s_and_s"
9
+ end
10
+
11
+ def self.down
12
+ remove_index :slugs, :name => "index_slugs_on_n_s_s_and_s"
13
+ remove_column :slugs, :scope
14
+ remove_column :slugs, :sequence
15
+ add_column :slugs, :updated_at, :datetime
16
+ add_index :slugs, [:name, :sluggable_type], :unique => true
17
+ end
18
+
19
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'friendly_id'
@@ -0,0 +1,13 @@
1
+ module FriendlyId
2
+
3
+ module Helpers
4
+ # Calculate expected result size for find_some_with_friendly (taken from
5
+ # active_record/base.rb)
6
+ def expected_size(ids_and_names, options) #:nodoc:#
7
+ size = options[:offset] ? ids_and_names.size - options[:offset] : ids_and_names.size
8
+ size = options[:limit] if options[:limit] && size > options[:limit]
9
+ size
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,40 @@
1
+ module FriendlyId::NonSluggableClassMethods
2
+
3
+ include FriendlyId::Helpers
4
+
5
+ def self.extended(base) #:nodoc:#
6
+ class << base
7
+ alias_method_chain :find_one, :friendly
8
+ alias_method_chain :find_some, :friendly
9
+ end
10
+ end
11
+
12
+ protected
13
+
14
+ def find_one_with_friendly(id, options) #:nodoc:#
15
+ if id.is_a?(String) && result = send("find_by_#{ friendly_id_options[:column] }", id, options)
16
+ result.send(:found_using_friendly_id=, true)
17
+ else
18
+ result = find_one_without_friendly id.to_i, options
19
+ end
20
+ result
21
+ end
22
+
23
+ def find_some_with_friendly(ids_and_names, options) #:nodoc:#
24
+
25
+ results = with_scope :find => options do
26
+ find :all, :conditions => ["#{ quoted_table_name }.#{ primary_key } IN (?) OR #{friendly_id_options[:column].to_s} IN (?)",
27
+ ids_and_names.map {|id| id.to_i}, ids_and_names.map {|id| id.to_s}]
28
+ end
29
+
30
+ expected = expected_size(ids_and_names, options)
31
+ if results.size != expected
32
+ raise ActiveRecord::RecordNotFound, "Couldn't find all #{ name.pluralize } with IDs (#{ ids_and_names * ', ' }) AND #{ sanitize_sql options[:conditions] } (found #{ results.size } results, but was looking for #{ expected })"
33
+ end
34
+
35
+ results.each {|r| r.send(:found_using_friendly_id=, true) if ids_and_names.include?(r.friendly_id)}
36
+
37
+ results
38
+
39
+ end
40
+ end