J'essaie de modifier une fonction qui, actuellement, n'accepte qu'une URL (chemin). chaîne de caractères - pour le rendre plus flexible, afin qu'il accepte également en entrée les mêmes arguments que ceux que vous pouvez passer à url_for
. Le problème est que, url_for
renvoie une URL complète incluant protocole/hôte, et je ne veux que la partie chemin...
url_for
a une belle only_path: true
qui lui permet de ne pas ajouter le protocole/hôte. Cela fonctionne très bien tant que vous le passez comme partie d'un seul hachage à url_for
:
main > app.url_for(controller: 'users', action: 'index', only_path: true)
=> "/users"
Mais comment passer des options lorsque l'on passe une tableau ou un objet modèle a url_for
?
main > app.url_for(user, only_path: true)
ArgumentError: wrong number of arguments (given 2, expected 0..1)
from /gems/actionpack-5.1.6/lib/action_dispatch/routing/url_for.rb:166:in `url_for'
main > app.url_for([user, :notification_preferences], only_path: true)
ArgumentError: wrong number of arguments (given 2, expected 0..1)
/actionpack-5.1.6/lib/action_dispatch/routing/url_for.rb:166:in `url_for'
Vous ne pouvez pas ! Clairement, il n'est même pas syntaxiquement possible de passer un hash d'options si vous passez autre chose qu'un hash, puisque il s arity est 0..1
et il ne prend qu'un seul argument : url_for(options = nil)
.
Ma question est donc la suivante : existe-t-il un assistant Rails qui prend les mêmes options que url_for
(y compris anchor:
) mais renvoie un chemin ?
Je suppose qu'il ne serait pas trop difficile d'en ajouter un, comme celui-ci qui utilise URI.parse(path).path
(probablement ce que je vais faire pour le moment)... mais cela semble inefficace, inélégant et incohérent.
Inefficace y inélégant car il génère une chaîne de caractères contenant des informations supplémentaires non souhaitées et doit ensuite l'analyser, la convertir en une structure de données structurée, puis la convertir arrière à une chaîne de caractères sans l'information non désirée.
Inconsistant parce que :
-
Rails comprend un
_path
variante pour chaque_url
aide à l'itinéraire. Pourquoi ne dispose-t-il pas d'une variante intégrée de "chemin" deurl_for
(ou le fait-il et s'appelle-t-il autrement ?) ? -
Autre les aides au routage qui acceptent un objet ou un tableau - comme
polymorphic_path
- vous permettent également de passer en option :
Exemple :
main > app.polymorphic_url [user, :notification_preferences], anchor: 'foo'
=> "http://example.com/users/4/notification_preferences#foo"
main > app.polymorphic_path [user, :notification_preferences], anchor: 'foo'
=> "/users/4/notification_preferences#foo"
main > app.polymorphic_path user, anchor: 'foo'
=> "/users/4#foo"
ActionDispatch::Routing::RouteSet
a en fait un path_for
:
# strategy for building urls to send to the client
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
def path_for(options, route_name = nil)
url_for(options, route_name, PATH)
end
# The +options+ argument must be a hash whose keys are *symbols*.
def url_for(options, route_name = nil, url_strategy = UNKNOWN)
options = default_url_options.merge options
...
- juste pas ActionDispatch::Routing::UrlFor
apparemment. En tout cas, ActionDispatch::Routing::RouteSet#path_for
est enfouie trop profondément dans les internes pour m'être utile ; j'ai besoin d'une aide qui puisse être appelée depuis le contrôleur/la vue.
Alors, quelle est la bonne solution pour cela qui soit élégante, cohérente avec les autres aides au routage de Rails, et relativement efficace (pas de URI.parse
) ?
Mieux encore, y a-t-il une raison pour que la signature de la méthode de l'élément intégré url_for
ne pourrait pas simplement être modifié (dans une future version de Rails, en soumettant une demande de téléchargement) pour permettre à la fois un sujet (objet de modèle, tableau ou hachage) y un nombre quelconque d'options options
à faire passer ?
Probablement l'original url_for
a été écrit avant que Ruby ne dispose d'arguments par mot-clé. Mais de nos jours, il est assez simple de faire exactement cela : accepter un "objet" plus un nombre quelconque d'options de mots-clés :
def url_for(object = nil, **options)
puts "object: #{object.inspect}"
puts "options: #{options.inspect}"
end
main > url_for ['user', :notification_preferences], anchor: 'anchor'
object: ["user", :notification_preferences]
options: {:anchor=>"anchor"}
=> nil
main > url_for ['user', :notification_preferences], only_path: true
object: ["user", :notification_preferences]
options: {:only_path=>true}
Y a-t-il une raison pour laquelle nous ne pourrions pas/ne devrions pas changer url_for
à la signature de la méthode url_for(object = nil, **options)
?
Comment modifieriez-vous url_for
/ full_url_for
de manière à ce qu'il reste aussi rétrocompatible que possible, tout en vous permettant de l'appeler avec un tableau + des options de mots-clés ?