2010-01-27 5 views
13

Je voudrais sortir un paramètre d'une URL par son nom sans savoir de quel paramètre il s'agit, et réassembler l'URL à nouveau.Quelle est la méthode la plus élégante de Ruby pour supprimer un paramètre d'une URL?

Je suppose qu'il n'est pas si difficile d'écrire quelque chose par moi-même en utilisant CGI ou URI, mais j'imagine qu'une telle fonctionnalité existe déjà. Aucune suggestion?

Dans:

http://example.com/path?param1=one&param2=2&param3=something3 

Out:

http://example.com/path?param2=2&param3=something3 

Répondre

7

Le adressable joyau va faire bien; s'il vous plaît voir la réponse supérieure par The Tin Man. Mais si vous voulez rouler le vôtre, voici comment. La demande que ce code a l'élégance est qu'il cache le laid dans une méthode:

#!/usr/bin/ruby1.8 

def reject_param(url, param_to_reject) 
    # Regex from RFC3986 
    url_regex = %r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$" 
    raise "Not a url: #{url}" unless url =~ url_regex 
    scheme_plus_punctuation = $1 
    authority_with_punctuation = $3 
    path = $5 
    query = $7 
    fragment = $9 
    query = query.split('&').reject do |param| 
    param_name = param.split(/[=;]/).first 
    param_name == param_to_reject 
    end.join('&') 
    [scheme_plus_punctuation, authority_with_punctuation, path, '?', query, fragment].join 
end 

url = "http://example.com/path?param1=one&param2=2&param3=something3" 
p url 
p reject_param(url, 'param2') 

# => "http://example.com/path?param1=one&param2=2&param3=something3" 
# => "http://example.com/path?param1=one&param3=something3" 
+2

Upvote pour l'utilisation de la regex réelle de la RFC. Excellente référence. – btelles

+2

Les points-virgules peuvent également être utilisés pour séparer les paramètres de requête, votre 'reject_param' ne fonctionne pas avec cette URL valide' http: //example.com/path? Param1 = one; param2 = 2; param3 = something3'. –

+0

@mu est trop court, merci. J'ai modifié (mais pas testé) le code pour permettre ';' ainsi que '='. –

5

je suis venu avec quelque chose comme ça

def uri_remove_param(uri, params = nil) 
    return uri unless params 
    params = Array(params) 
    uri_parsed = URI.parse(uri) 
    return uri unless uri_parsed.query 
    escaped = uri_parsed.query.grep(/&/).size > 0 
    new_params = uri_parsed.query.gsub(/&/, '&').split('&').reject { |q| params.include?(q.split('=').first) } 
    uri = uri.split('?').first 
    amp = escaped ? '&' : '&' 
    "#{uri}?#{new_params.join(amp)}" 
end 
+0

Donnez-vous la coche; J'aime mieux ta réponse. URI.parse? Encore une autre bibliothèque pratique dont je ne connaissais rien. Oh, tes params = [params] si ... line? Vous pouvez le remplacer par params = Array (params). J'ai appris cette astuce sur SO, bien sûr. –

+0

params = Array (params) est cool! – dimus

+1

après avoir joué avec Array (params) pendant un moment ... Array ({}) doit être utilisé avec précaution car il convertit aussi hash en array. – dimus

26

Peut-être un peu hors sujet, mais pour tous ceux qui est essayer de le faire dans le contexte d'une application rails, vous pouvez simplement faire:

url_for(params.except(:name_of_param_to_delete)) 

NB Testé dans les rails v2.3.9.

+0

et le contraire de 'except' est' tranche ' – lulalala

+0

Solution très intelligente! – Gunchars

+0

Vraiment sympa, merci! – Agustin

31

Je préfère utiliser:

require 'addressable/uri' 

uri = Addressable::URI.parse('http://example.com/path?param1=one&param2=2&param3=something3') 

params = uri.query_values #=> {"param1"=>"one", "param2"=>"2", "param3"=>"something3"} 
params.delete('param1') #=> "one" 
uri.query_values = params #=> {"param2"=>"2", "param3"=>"something3"} 

uri.to_s #=> "http://example.com/path?param2=2&param3=something3" 
+1

A travaillé comme un charme! Github page pour addressable: https://github.com/sporkmonger/addressable/tree/ – ankimal

+2

Ceci est _so_ beaucoup plus agréable que ma solution. –

15

Si vous ne voulez pas inclure un petit bijou supplémentaire et si vous ne voulez pas Regex méchant, voici ma façon préférée:

require 'cgi' 
require 'uri' 

url = "http://example.com/path?param1=one&param2=2&param3=something3" 

uri = URI(url) #=> #<URI::HTTP:0x007fbe25141a78 URL:http://example.com/path?param1=one&param2=2&param3=something3> 
params = CGI.parse(uri.query || "") #=> {"param1"=>["one"], "param2"=>["2"], "param3"=>["something3"]} 
params.delete('param1') #=> ["one"] 
uri.query = URI.encode_www_form(params) #=> "param2=2&param3=something3" 

uri.to_s #=> "http://example.com/path?param2=2&param3=something3" 
+1

+ 1 pour l'utilisation de stdlib – Puhlze

+2

Je voudrais modifier l'analyse CGI comme pour gérer les paramètres manquants ... 'CGI.parse (uri.query ||" ")' sinon l'analyse soulève une exception. –

3

One ligne devrait être assez:

url.sub(/\?param_to_remove=[^&]*/, '?').sub(/\&param_to_remove=[^&]*/, '').sub(/\?$/,'') 
+0

Juste ce que je cherchais! Merci! – viniciusnz

+0

incorrect pour le cas où param_to_remove va en premier –

Questions connexes