0

I have friendly_id setup properly and everything works, using slugs.

The issue I am having is that some of the names on my Tag model (which is the model that FriendlyId is attached to) need to be HTML escaped.

Names like c++ or .net.

When I ran Tag.find_each(:&save), it generated all the slugs for me....but on those tags with those names, this is what happened:

> c = Tag.where(:name => "c++")
  Tag Load (0.9ms)  SELECT "tags".* FROM "tags" WHERE "tags"."name" = 'c++'
 => [#<Tag id: 2, name: "c++", num_questions: 187598, created_at: "2013-03-23 07:02:09", updated_at: "2013-03-29 15:34:09", questions_count: 87, slug: "c">] 
> Tag.where(:name => ".net")
  Tag Load (0.9ms)  SELECT "tags".* FROM "tags" WHERE "tags"."name" = '.net'
 => [#<Tag id: 142, name: ".net", num_questions: 149074, created_at: "2013-03-23 07:09:47", updated_at: "2013-03-29 15:34:10", questions_count: 85, slug: "net">] 
1.9.3p392 :012 > Tag.where(:name => "c#")
  Tag Load (1.0ms)  SELECT "tags".* FROM "tags" WHERE "tags"."name" = 'c#'
 => [#<Tag id: 38, name: "c#", num_questions: 435620, created_at: "2013-03-23 07:03:27", updated_at: "2013-03-29 15:34:10", questions_count: 130, slug: "c--3">] 

Notice the slugs on each of those - and how they don't correspond properly to the name of each record.

How do I fix this?

marcamillion
  • 32,933
  • 55
  • 189
  • 380

1 Answers1

1

friendly_id (at least when you call it with :use => :slugged) tries to "clean up" the field value so that it will look nice in a URL. If you want to change that behavior, you can override normalize_friendly_id. If you do that, you'll need to be sure to URL-encode your slugs though, because things like # already have special meaning in URLs.

For anyone coming across this later, the working solution was to avoid using friendly_id's :use_slugged, instead just using the raw names of the tags and having them automatically escaped by Rails' link helpers. For the ".net" tag, it also required the routes to be changed to resources :tags, :constraints => { :id => /.*/ } to keep Rails from interpreting the dot as a path separator.

Dan Wich
  • 4,923
  • 1
  • 26
  • 22
  • Soo....without getting as complicated as that...how do I just allow for those simple names to work like I want? – marcamillion Mar 29 '13 at 17:14
  • I assume you need the slugs to appear in URLs? If so, how do you want "problem characters" like these to be handled? Especially for the `#` sign, you'll either have to replace it or URL-encode it. – Dan Wich Mar 29 '13 at 17:18
  • As you correctly pointed out, `normalize_friendly_id` all it does is calls `parameterize` on the string - https://github.com/norman/friendly_id/blob/master/lib/friendly_id/slugged.rb#L244 What I want to do, though, is to get these strings working. When I do `c#.parameterize` in my Rails console, I get `> "c#".parameterize => "c" ` Which is exactly what I don't want. – marcamillion Mar 29 '13 at 17:18
  • I don't mind URL-encoding it. What would the URL-encoded version of `tags/c#` look like? Hopefully not `tags/c` because that is wrong in this situation. – marcamillion Mar 29 '13 at 17:19
  • Ok. As long as you don't care that the tag names will be URL-encoded when you put them in a view, you could remove `:use => slugged` and just use your tag name as the "slug". This is similar to what Stack Overflow does, you can see that they've URL-encoded the C# tag, for example: http://stackoverflow.com/questions/tagged/c%23 – Dan Wich Mar 29 '13 at 17:20
  • Well the thing is, if you look at the `Tag.name` of my `c#` record, you will see that the name isn't URL-encoded. It is just `c#`. So I guess I need to URL-encode the names of my tags? – marcamillion Mar 29 '13 at 17:33
  • Also...if I were to URL-encode the names of my tag, how would I de-code them in my views? Is there a rails helper for that? – marcamillion Mar 29 '13 at 17:35
  • You can just URL-encode them when you output them to your view, no need to do anything in the model. You'll have to test this, but I believe the built-in link_to/tag_path helpers will do the encoding for you. If you see in your source HTML that your C# tag path is "/tags/c%23", you'll know it worked. – Dan Wich Mar 29 '13 at 17:48
  • Ok that works. What about `.net`? It still says the slug is `net` as opposed to `.net`. – marcamillion Mar 29 '13 at 17:53
  • I'm thinking you should remove the separate slug field (along with removing `:use => :slugged` so that you always use the whole name field as your slug. – Dan Wich Mar 29 '13 at 17:59
  • If I remove the `use: :slugged` it breaks it even more. `.net` gives me a Routing error. – marcamillion Mar 29 '13 at 18:12
  • How do I escape url-encoded URLs in link_tag helpers? i.e. when I do `<%= "Top #{(params[:id])} Questions"%>` that prints out `Top c# Questions` - like you would expect. However, when I do `<%= link_to "#{tag.name}", tag_path(tag) %>`, that prints out a link with the name `c%23` instead of `c#`. How do I get the link to print `c#`? – marcamillion Mar 29 '13 at 18:18
  • Hmm, is the name of the link printing c%23, or is the URL itself using c%23? The URL itself should use c%23 because using a raw # would cause problems. – Dan Wich Mar 29 '13 at 18:29
  • Yes, the URL itself is using `c%23`, but...I want it to print `c#` as the name of the actual link...but it's printing `c%23`. – marcamillion Mar 29 '13 at 18:31