friendly_id4 4.0.0.beta1

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