Friendly_id is a plugin for Ruby on Rails which allows you to work with human-friendly strings as well as numeric ids for ActiveRecords, so that you can have urls like “/members/joe” rather than “/members/123” or “/members/123-joe”.
This provides your application with better search engine optimization (SEO), better data security, and more human-friendly URL’s.It can optionally keep track of modified ids, so that you can do 301 redirects the current URL’s of updated resources.
Read more in the RDoc, or download it directly from its subversion repository.
All patches and recommendations posted in the comments have now been applied to svn. Thanks again to suntzu, W. Andrew Loe III, and Emilio Tagua for their contributions.
I’m having trouble when running the ‘rake riendly_id:make_slugs’ task. It fails on line 250 of friendly_id.rb (”I give up, damnit!”) when trying to make a slug for an item named “Post”. I’ve traced the issue to another item named “Post 2/4″, which gets slugged to “post-2-4″, then trips up the generate_friendly_id_with_extension method. What’s the best way to handle this type of case?
Thanks!
Thanks for the bug report. I’ve committed a fix to svn that should resolve this issue for you. Let me know how it works out.
Thanks, Norman, the new code looks to be working like a charm!
Suggestions for instruction set:
Was reading http://agilewebdevelopment.com/plugins/friendly_id and got quite confused at one point when under Scenario 2 (for sluggables) it says:
has_friendly_id :posts, :use_slug => true
This should say something more like:
has_friendly_id :post_title, :use_slug => true
Also -
Ran ‘rake friendly_id:make_slugs MODEL=MyModelName’ on one of my models and for some reason it came back telling me I had validation errors based on the validations I was using in my model:
Validation failed: Tag list Can only be letters and numbers
Validation failed: Advice wording is too short (minimum is 10 characters)
Not sure why that happened since it shouldn’t be creating any new records outside of the slugs table, right?
Sorry to post yet again -
I got around that validation problem on the last part by just removing the validations from my model, running the rake task and then putting them back. Everything seems to work fine.
The rdoc isn’t in sync with the source… noticed during ‘Setup’ instructions in readme. The rdoc points to a tags/1_0 but that doesn’t exist. The readme in truck points to trunk.
Just noticed the discrepancy between these two statements in the README
“Also, any person can still simply increment the id part of the url, and gain a level of access to your data that you may not wish them to have.”
“# Post.find(1) still works, too”
So one can still hit http://www.example.org/profiles/12 and have it call up Joe since a Profile.find(12) was sent through… What do you recommend to prevent people calling up records by id?
@Chris Nolan.ca
You can always wrap the find method and use the wrapped version in your controllers.
def find_friendly(id)
if( id.to_i == 0 ) # 0 is default and not a valid id
find( id ) # or throw an error
else
find_by_id( id ) || find( id )
end || raise (ActionController::RoutingError, “unkown resource: #{id}”)
FYI Model.exists? fails when using the slug.
I’m running into trouble updating a record which is the first of 19 identically-named objects, i.e. the latest slug is “name-19″. The call to Slug.count_matches in generate_friendly_id_with_extension returns 18 (because the id of the record being updated is excluded), this gets incremented to 19, then a SlugGenerationError gets thrown at friendly_id.rb:251 due to the collision with the existing name-19 slug. I haven’t had time yet to trace exactly what logic is failing, but maybe the regexp in Slug.count_matches should capture the highest extension number rather than doing a simple count and increment? Or maybe the increment logic just needs a tweak?
Thanks!
I’ve incoroportated the documentation changes suggested above. Thanks!
@Jeff, we are working on your problem. Sorry, I was on vacation for a while, got back and have been playing catch-up at work. We’ll have a solution posted soon.
when I use friendly id without :use_slug => true on a model, it doesn’t sanitize the friendly id. In order to fix this and make it behave properly I just did,
Slug::normalize(send(friendly_id_options[:method].to_sym))
on line 104 of lib/friendly_id.rb
I’m not sure whether this is the best solution, but it’s the best five minute solution I could come up with.
Max, the non-sanitizing behavior when not using slugs is actually intentional, so as not to overwrite people’s data. Not using slugs is sort of a “roll your own” option; to be used if you already have your own way to sanitize strings and ensure their uniqueness.
I think the documentation is probably lacking, also perhaps I could make it an available option for people that do want to use it.
ah, gotcha. That makes sense. I wouldn’t mind having the option, but that’s good to know. I thought it was a little bit too much of a blatant oversight, considering that it’s tested pretty well.
So when I am my main User model with a unique username that I will be using with friendly_id, I don’t need to run the rake/migrate tasks? It won’t use the slogs table?
@Jeremy
Yes, exactly.
I am using friendly_id on my user model. I get an error when there is more than one user with the same name. When I have for example users: John, John-1, John-2 and than John tries to login(updates the user model), I get: “I give up, damnit!”.
John-2 can update his info with no problems.
If I understand correctly this problem is similar to the problem Jeff described.
How can I get this to work?
Miha, I’ve committed a fix to svn that should hopefully resolve this issue.
Is it possible to use this on more than one model at the same time, and particularly on nested routes?
I have categories and subcategories (url: /categories/:id/subcategories/:id/) and would like to change both :ids with slugs.
@Flavio
Yeah, it works fine. I am using the plugin in several applications with nested routes and url’s similar to what you described. Just let me know if you encounter any difficulties.