2010-12-09 39 views
11

J'essaie donc d'utiliser une aide URL Rails (page_url) pour créer des URL qui contiennent des caractères spéciaux, y compris des esperluettes. La plupart des cas de travail comme vous le feriez attendez à:Rails url helper ne pas encoder les esperluettes

(rdb:1) page_url('foo', :host => 'host') 
"http://host/pages/foo" 
(rdb:1) page_url('foo_%_bar', :host => 'host') 
"http://host/pages/foo_%25_bar" 

Mais pour une raison étrange, esperluette ne sont pas échappés:

(rdb:1) page_url('foo_&_bar', :host => 'host') 
"http://host/pages/foo_&_bar" 

Et si je les pré-évasion, ils sont endommagés:

(rdb:1) page_url('foo_%26_bar', :host => 'host') 
"http://host/pages/foo_%2526_bar" 

CGI::escape, d'autre part, leur échappe bien:

(rdb:1) CGI::escape('foo_&_bar') 
"foo_%26_bar" 

Que se passe-t-il et comment puis-je contourner ce problème? (Avec quelque chose de plus beau que gsub('&', '%26'), c'est-à-dire.)

+0

Hmmm .. Je ne trouve pas d'aide-rails spécifiquement nommée page_url (consulté sur le site web d'apidock) - êtes-vous sûr que c'est le bon nom de méthode? Voulez-vous dire url_for à la place? –

+0

J'ai un ActiveRecord appelé "page", l'assistant _url pour cela est créé automagiquement. – jpatokal

+0

Ah - c'est vrai. Cela n'est pas apparu dans votre description :) –

Répondre

14

Je ne peux pas vous dire une meilleure façon d'y faire face - mais je peux expliquer pourquoi cela se passe.

Les amorces ne sont pas des caractères non valides pour une URL. Sinon, vous auriez des problèmes avec: "http://host/pages/foo?bar=baz&style=foo_style" ou autre. En creusant plus profondément dans le code source, il semble que Rails utilise CGI.escape uniquement sur les paramètres.

L'aide, utilisez url générateurs url_for (sous les couvertures), qui appelle finalement: http://apidock.com/rails/ActionController/Routing/Route/generate Ce qui appelle des choses profondes dans les méthodes de sprivate-du code source ... mais finit éventuellement par appeler cgi.escape (regardez d'abord dans actionpack/lib/action_controller/routing/route.rb puis dans actionpack/lib/action_controller/routing/segments.rb)

Le résultat final est que sur l'url lui-même, les rails utilisent URI.escape - ce qui est notamment le cas pas mettre à jour esperluette du tout:

>> CGI.escape('/my_foo_&_bar') 
=> "%2Fmy_foo_%26_bar" 
>> URI.escape('/my_foo_&_bar') 
=> "/my_foo_&_bar" 

Il y a actuellement rien que vous pouvez faire à ce sujet sans mettre une demande de fonctionnalité réelle sur l'équipe des rails.

... sauf si vous avez la possibilité de choisir de ne pas utiliser l'esperluette dans vos URL Vous pouvez toujours les gsub vous-même pour toutes les URL:

def my_clean_url(the_url) 
    return the_url.gsub(/&/,'_') 
end 
>> my_clean_url('/my_foo_&_bar') 
=> "/my_foo___bar" 

page_url(my_clean_url('/my_foo_&_bar')) 
+1

Le problème est que le & est utilisé par l'application sous-jacente (non-Ruby) comme un caractère normal, mais de nombreux analyseurs d'URL le voient comme un délimiteur de paramètre et découpent l'URL lorsqu'ils le voient. L'encodage fait en sorte qu'il reste intact. – jpatokal

+0

Ah yup - c'est logique. –

+0

Merci pour le travail de détective! – jpatokal

6

Pour tous ceux qui essaient de coder ne importe quoi autres que az, AZ, 0-9 et underscore:

URI.encode(string, /\W/) 

Supposons que vous avez un contenu qui peut contenir par exemple esperluette et vous voulez utiliser ce contenu comme paramètre body pour un lien mailto: Sans /\W/, l'esperluette (qui est un caractère URI sûr) ne serait pas encodée et donc romprait partiellement le lien.