friendly_id4 4.0.0.beta1

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.
@@ -0,0 +1,11 @@
1
+ Gemfile
2
+ Gemfile.lock
3
+ doc
4
+ docs
5
+ pkg
6
+ .DS_Store
7
+ coverage
8
+ .yardoc
9
+ *.gem
10
+ *.sqlite3
11
+ *.rbc
@@ -0,0 +1,368 @@
1
+ # FriendlyId Guide
2
+
3
+ * Table of Contents
4
+ {:toc}
5
+
6
+ ## Overview
7
+
8
+ FriendlyId is an ORM-centric Ruby library that lets you work with human-friendly
9
+ strings as if they were numeric ids. Among other things, this facilitates
10
+ replacing "unfriendly" URL's like:
11
+
12
+ http://example.com/states/4323454
13
+
14
+ with "friendly" ones such as:
15
+
16
+ http://example.com/states/washington
17
+
18
+ FriendlyId is typically used with Rails and Active Record, but can also be used in
19
+ non-Rails applications.
20
+
21
+ ## Simple Models
22
+
23
+ The simplest way to use FriendlyId is with a model that has a uniquely indexed
24
+ column with no spaces or special characters, and that is seldom or never
25
+ updated. The most common example of this is a user name or login column:
26
+
27
+ class User < ActiveRecord::Base
28
+ validates_format_of :login, :with => /\A[a-z0-9]+\z/i
29
+ has_friendly_id :login
30
+ end
31
+
32
+ @user = User.find "joe" # the old User.find(1) still works, too
33
+ @user.to_param # returns "joe"
34
+ redirect_to @user # the URL will be /users/joe
35
+
36
+ In this case, FriendlyId assumes you want to use the column as-is; it will never
37
+ modify the value of the column, and your application should ensure that the value
38
+ is admissible in a URL:
39
+
40
+ class City < ActiveRecord::Base
41
+ has_friendly_id :name
42
+ end
43
+
44
+ @city.find "Viña del Mar"
45
+ redirect_to @city # the URL will be /cities/Viña%20del%20Mar
46
+
47
+ For this reason, it is often more convenient to use Slugs rather than a single
48
+ column.
49
+
50
+ ## Slugged Models
51
+
52
+ FriendlyId uses a separate column to store slugs for models which require some
53
+ processing of the friendly_id text. The most common example is a blog post's
54
+ title, which may have spaces, uppercase characters, or other attributes you
55
+ wish to modify to make them more suitable for use in URL's.
56
+
57
+ class Post < ActiveRecord::Base
58
+ include FriendlyId::Slugged
59
+ has_friendly_id :title
60
+ end
61
+
62
+ @post = Post.create(:title => "This is the first post!")
63
+ @post.friendly_id # returns "this-is-the-first-post"
64
+ redirect_to @post # the URL will be /posts/this-is-the-first-post
65
+
66
+ If you are unsure whether to use slugs, then your best bet is to use them,
67
+ because FriendlyId provides many useful features that only work with this
68
+ feature. These features are explained in detail {file:Guide.md#features below}.
69
+
70
+ ## Installation
71
+
72
+ gem install friendly_id
73
+
74
+ After installing the gem, add an entry in the Gemfile:
75
+
76
+ gem "friendly_id", "~> 4.0.0"
77
+
78
+ ### Future Compatibility
79
+
80
+ FriendlyId will always remain compatible with the current release of Rails, and
81
+ at least one stable release behind. That means that support for 3.0.x will not be
82
+ dropped until a stable release of 3.2 is out, or possibly longer.
83
+
84
+ ## Configuration
85
+
86
+ FriendlyId is configured in your model using the `has_friendly_id` method. Additional
87
+ features can be activated by including various modules:
88
+
89
+ class Post < ActiveRecord::Base
90
+ # use slugs
91
+ include FriendlyId::Slugged
92
+ # record slug history
93
+ include FriendlyId::History
94
+ # use the "title" accessor as the basis of the friendly_id
95
+ has_friendly_id :title
96
+ end
97
+
98
+ Read on to learn about the various features that can be configured. For the
99
+ full list of valid configuration options, see the instance attribute summary
100
+ for {FriendlyId::Configuration}.
101
+
102
+ # Features
103
+
104
+ ## FriendlyId Strings
105
+
106
+ By default, FriendlyId uses Active Support's Transliterator class to convert strings into
107
+ ASCII slugs by default. Please see the API docs for
108
+ [transliterate](http://api.rubyonrails.org/) and
109
+ [parameterize](http://api.rubyonrails.org/) to see what options are avaialable
110
+ to you.
111
+
112
+ Previous versions of FriendlyId used [Babosa](github.com/norman/babosa) for slug
113
+ string handling, but the core functionality it provides was extracted from it
114
+ and added to Rails 3. However, Babosa offers some advanced functionality not
115
+ offered by Rails and can still be a convenient option. This section shows how
116
+ you can use it with FriendlyId.
117
+
118
+ ### Using a Custom Method to Generate the Slug Text
119
+
120
+ FriendlyId can use either a column or a method to generate the slug text for
121
+ your model:
122
+
123
+ class City < ActiveRecord::Base
124
+
125
+ belongs_to :country
126
+ include FriendlyId::Slugged
127
+ has_friendly_id :name_and_country
128
+
129
+ def name_and_country
130
+ #{name} #{country.name}
131
+ end
132
+
133
+ end
134
+
135
+ @country = Country.create(:name => "Argentina")
136
+ @city = City.create(:name => "Buenos Aires", :country => @country)
137
+ @city.friendly_id # will be "buenos-aires-argentina"
138
+
139
+ One word of caution: in the example above, if the country's name were updated,
140
+ say, to "Argentine Republic", the city's friendly_id would not be
141
+ automatically updated. For this reason, it's a good idea to avoid using
142
+ frequently-updated relations as a part of the friendly_id.
143
+
144
+ ## Using a Custom Method to Process the Slug Text
145
+
146
+ If the built-in slug text handling options don't work for your application,
147
+ you can override the `normalize_friendly_id` method in your model class in
148
+ order to fine-tune the output:
149
+
150
+ class City < ActiveRecord::Base
151
+
152
+ include FriendlyId::Slugged
153
+ has_friendly_id :whatever
154
+
155
+ def normalize_friendly_id(text)
156
+ my_text_modifier_method(text)
157
+ end
158
+
159
+ end
160
+
161
+ The `normalize_friendly_id` method takes a single argument and receives an
162
+ instance of {FriendlyId::SlugString}, a class which wraps a regular Ruby string
163
+ with additional formatting options.
164
+
165
+ ### Converting non-Latin characters to ASCII with Babosa
166
+
167
+ Babosa offers the ability to idiomatically transliterate non-ASCII characters
168
+ to ASCII:
169
+
170
+ "Jürgen".to_slug.normalize! #=> "Jurgen"
171
+ "Jürgen".to_slug.normalize! :transliterate => :german #=> "Juergen"
172
+
173
+ Using Babosa with FriendlyId is a simple matter of installing and requiring
174
+ the `babosa` gem, and overriding the `normalize_friendly_id` method in your
175
+ model:
176
+
177
+ class City < ActiveRecord::Base
178
+ def normalize_friendly_id(text)
179
+ text.slug.normalize!
180
+ end
181
+ end
182
+
183
+ ## Redirecting to the Current Friendly URL
184
+
185
+ FriendlyId can maintain a history of your record's older slugs, so if your
186
+ record's friendly_id changes, your URL's won't break.
187
+
188
+ class Post < ActiveRecord::Base
189
+ include FriendlyId::Slugged
190
+ include FriendlyId::History
191
+ has_friendly_id :title
192
+ end
193
+
194
+ class PostsController < ApplicationController
195
+
196
+ before_filter :find_post
197
+
198
+ ...
199
+ def find_post
200
+ return unless params[:id]
201
+ @post = begin
202
+ Post.find params[:id]
203
+ rescue ActiveRecord::RecordNotFound
204
+ Post.find_by_friendly_id params[:id]
205
+ end
206
+ # If an old id or a numeric id was used to find the record, then
207
+ # the request path will not match the post_path, and we should do
208
+ # a 301 redirect that uses the current friendly_id
209
+ if request.path != post_path(@post)
210
+ return redirect_to @post, :status => :moved_permanently
211
+ end
212
+ end
213
+ end
214
+
215
+ ## Non-unique Slugs
216
+
217
+ FriendlyId will append a arbitrary number to the end of the id to keep it
218
+ unique if necessary:
219
+
220
+ /posts/new-version-released
221
+ /posts/new-version-released--2
222
+ /posts/new-version-released--3
223
+ ...
224
+ etc.
225
+
226
+ Note that the number is preceded by "--" rather than "-" to distinguish it from
227
+ the rest of the slug. This is important to enable having slugs like:
228
+
229
+ /cars/peugeot-206
230
+ /cars/peugeot-206--2
231
+
232
+ You can configure the separator string used by your model by setting the
233
+ `:sequence_separator` option in `has_friendly_id`:
234
+
235
+ include FriendlyId::Slugged
236
+ has_friendly_id :title, :sequence_separator => ":"
237
+
238
+ You can also override the default used in
239
+ {FriendlyId::Configuration::DEFAULTS} to set the value for any model using
240
+ FriendlyId. If you change this value in an existing application, be sure to
241
+ {file:Guide.md#regenerating_slugs regenerate the slugs} afterwards.
242
+
243
+ For reasons I hope are obvious, you can't change this value to "-". If you try,
244
+ FriendlyId will raise an error.
245
+
246
+ ## Reserved Words
247
+
248
+ When you use slugs, FriendlyId adds a validation to avoid using "new" and
249
+ "index" as slugs. You can control the default reserved words by changing the
250
+ value in `FriendlyId::Configuration::DEFAULTS[:reserved_words]`.
251
+
252
+ ## Scoped Slugs
253
+
254
+ FriendlyId can generate unique slugs within a given scope. For example, assume
255
+ you have an application that displays restaurants. Without scoped slugs, if two
256
+ restaurants are named "Joe's Diner," the second one will end up with
257
+ "joes-diner--2" as its friendly_id. Using scoped allows you to keep the slug
258
+ names unique for each city, so that the second "Joe's Diner" can also have the
259
+ slug "joes-diner", as long as it's located in a different city:
260
+
261
+ class Restaurant < ActiveRecord::Base
262
+ belongs_to :city
263
+ include FriendlyId::Slugged
264
+ include FriendlyId::Scoped
265
+ has_friendly_id :name, :scope => :city
266
+ end
267
+
268
+ class City < ActiveRecord::Base
269
+ has_many :restaurants
270
+ include FriendlyId::Slugged
271
+ has_friendly_id :name
272
+ end
273
+
274
+ City.find("seattle").restaurants.find("joes-diner")
275
+ City.find("chicago").restaurants.find("joes-diner")
276
+
277
+
278
+ The value for the `:scope` key in your model can be a column, or the name of a
279
+ relation.
280
+
281
+ ### Complications with Scoped Slugs
282
+
283
+ #### Finding Records by friendly\_id
284
+
285
+ If you are using scopes your friendly ids may not be unique, so a simple find like
286
+
287
+ Restaurant.find("joes-diner")
288
+
289
+ may return the wrong record. In these cases when you want to use the friendly\_id for queries,
290
+ either query as a relation, or specify the scope in your query conditions:
291
+
292
+ # will only return restaurants named "Joe's Diner" in the given city
293
+ @city.restaurants.find("joes-diner")
294
+
295
+ # or
296
+
297
+ Restaurants.find("joes-diner").where(:city_id => @city.id)
298
+
299
+
300
+ #### Finding All Records That Match a Scoped ID
301
+
302
+ If you want to find all records with a particular friendly\_id regardless of scope,
303
+ the easiest way is to use cached slugs and query this column directly:
304
+
305
+ Restaurant.find_all_by_slug("joes-diner")
306
+
307
+ ### Routes for Scoped Models
308
+
309
+ Note that FriendlyId does not set up any routes for scoped models; you must do
310
+ this yourself in your application. Here's an example of one way to set this up:
311
+
312
+ # in routes.rb
313
+ resources :cities do
314
+ resources :restaurants
315
+ end
316
+
317
+ # in views
318
+ <%= link_to 'Show', [@city, @restaurant] %>
319
+
320
+ # in controllers
321
+ @city = City.find(params[:city_id])
322
+ @restaurant = @city.restaurants.find(params[:id])
323
+
324
+ # URL's:
325
+ http://example.org/cities/seattle/restaurants/joes-diner
326
+ http://example.org/cities/chicago/restaurants/joes-diner
327
+
328
+
329
+ # Misc tips
330
+
331
+ ## Default Scopes
332
+
333
+ Whether you're using FriendlyId or not, a good rule of thumb for default scopes
334
+ is to always use your model's table name. Otherwise any time you do a join, you
335
+ risk having queries fail because of duplicate column names - particularly for a
336
+ default scope like this one:
337
+
338
+ default_scope :order => "created_at DESC"
339
+
340
+ Instead, do this:
341
+
342
+ default_scope :order => = "#{quoted_table_name}.created_at DESC"
343
+
344
+ Or even better, unless you're using a custom primary key:
345
+
346
+ default_scope :order => = "#{quoted_table_name}.id DESC"
347
+
348
+ because sorting by a unique integer column is faster than sorting by a date
349
+ column.
350
+
351
+ ## Some Benchmarks
352
+
353
+ These benchmarks can give you an idea of FriendlyId's impact on the
354
+ performance of your application. Of course your results may vary.
355
+
356
+ activerecord (3.0.9)
357
+ ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0]
358
+ friendly_id (4.0.0.pre3)
359
+ sqlite3 (1.3.3) gem
360
+ sqlite3 3.6.12 in-memory database
361
+
362
+ user system total real
363
+ find (without FriendlyId) 0.280000 0.000000 0.280000 ( 0.278086)
364
+ find (in-table slug) 0.320000 0.000000 0.320000 ( 0.320151)
365
+ find (external slug) 3.040000 0.010000 3.050000 ( 3.048054)
366
+ insert (without FriendlyId) 0.780000 0.000000 0.780000 ( 0.785427)
367
+ insert (in-table-slug) 1.520000 0.010000 1.530000 ( 1.532350)
368
+ insert (external slug) 3.310000 0.020000 3.330000 ( 3.335548)
@@ -0,0 +1,92 @@
1
+ <hr>
2
+ **NOTE** This is FriendlyId4 - a rewrite of FriendlyId. For more info about this
3
+ rewrite, and the changes it brings, read [this
4
+ document](https://github.com/norman/friendly_id_4/blob/master/ABOUT.md).
5
+
6
+ For the current stable FriendlyId, please see:
7
+
8
+ [https://github.com/norman/friendly_id](https://github.com/norman/friendly_id_4)
9
+ <hr>
10
+ # FriendlyId
11
+
12
+ FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for
13
+ Ruby on Rails. It allows you to create pretty URL's and work with
14
+ human-friendly strings as if they were numeric ids for Active Record models.
15
+
16
+ Using FriendlyId, it's easy to make your application use URL's like:
17
+
18
+ http://example.com/states/washington
19
+
20
+ instead of:
21
+
22
+ http://example.com/states/4323454
23
+
24
+ ## FriendlyId Features
25
+
26
+ FriendlyId offers many advanced features, including: slug history and
27
+ versioning, scoped slugs, reserved words, custom slug generators, and
28
+ excellent Unicode support. For complete information on using FriendlyId,
29
+ please see the [FriendlyId Guide](http://norman.github.com/friendly_id/file.Guide.html).
30
+
31
+ FriendlyId is compatible with Active Record **3.0** and **3.1**.
32
+
33
+ ## Docs, Info and Support
34
+
35
+ * [FriendlyId Guide](http://norman.github.com/friendly_id/file.Guide.html)
36
+ * [API Docs](http://norman.github.com/friendly_id)
37
+ * [Google Group](http://groups.google.com/group/friendly_id)
38
+ * [Source Code](http://github.com/norman/friendly_id/)
39
+ * [Issue Tracker](http://github.com/norman/friendly_id/issues)
40
+
41
+ ## Rails Quickstart
42
+
43
+ gem install friendly_id
44
+
45
+ rails new my_app
46
+
47
+ cd my_app
48
+
49
+ # add to Gemfile
50
+ gem "friendly_id", "~> 4.0.0"
51
+
52
+ rails generate scaffold user name:string slug:string
53
+
54
+ # edit db/migrate/*_create_users.rb
55
+ add_index :users, :slug, :unique => true
56
+
57
+ rake db:migrate
58
+
59
+ # edit app/models/user.rb
60
+ class User < ActiveRecord::Base
61
+ include FriendlyId::Slugged
62
+ has_friendly_id :name
63
+ end
64
+
65
+ User.create! :name => "Joe Schmoe"
66
+
67
+ rails server
68
+
69
+ GET http://localhost:3000/users/joe-schmoe
70
+
71
+ ## Bugs
72
+
73
+ Please report them on the [Github issue tracker](http://github.com/norman/friendly_id/issues)
74
+ for this project.
75
+
76
+ If you have a bug to report, please include the following information:
77
+
78
+ * **Version information for FriendlyId, Rails and Ruby.**
79
+ * Stack trace and error message.
80
+ * Any snippets of relevant model, view or controller code that shows how your
81
+ are using FriendlyId.
82
+
83
+ If you are able to, it helps even more if you can fork FriendlyId on Github,
84
+ and add a test that reproduces the error you are experiencing.
85
+
86
+ ## Credits
87
+
88
+ FriendlyId was created by Norman Clarke, Adrian Mugnolo, and Emilio Tagua, and
89
+ has had significant contributions over the years from [many
90
+ volunteers](https://github.com/norman/friendly_id/contributors).
91
+
92
+ Copyright (c) 2008-2011 Norman Clarke, released under the MIT license.