¿Cómo extraer parámetros de URL de una URL con Ruby o Rails?

137

Tengo algunas URL, como

http://www.example.com/something?param1=value1&param2=value2&param3=value3

y me gustaría extraer los parámetros de estas URL y ponerlos en un hash. Obviamente, podría usar expresiones regulares, pero me preguntaba si había formas más fáciles de hacerlo con Ruby o Rails. No he encontrado nada en el módulo Ruby, URIpero tal vez me perdí algo.

De hecho, necesito un método que haga eso:

extract_parameters_from_url("http://www.example.com/something?param1=value1&param2=value2&param3=value3")
#=> {:param1 => 'value1', :param2 => 'value2', :param3 => 'value3'}

¿Te darías algunos consejos?

Flackou
fuente
1
Hash[*string.split('&').collect{|i|i.split('=')}.flatten] Esto también funcionaría, pero probablemente sea la peor opción para este caso. Pero aún así puede encontrar este fragmento interesante. (Publicando como comentario ya que no considero que esto sea una respuesta :-))
Vojto

Respuestas:

162

¿Creo que quieres convertir cualquier cadena URL en un HASH?

Puede probar http://www.ruby-doc.org/stdlib/libdoc/cgi/rdoc/classes/CGI.html#M000075

require 'cgi'

CGI::parse('param1=value1&param2=value2&param3=value3')

devoluciones

{"param1"=>["value1"], "param2"=>["value2"], "param3"=>["value3"]}
Francotirador
fuente
1
OK, ese fue el que me perdí! Es perfecto cuando se usa con URI.parse: CGI.parse (URI.parse (" example.com/… ) devuelve el hash deseado. Gracias por su ayuda.
Flackou
9191
Para mayor claridad, @Flackou quiere esto: CGI.parse(URI.parse(url).query)
Glenn Jackman
No he probado esto, pero la primera clave enumerada, que contiene la URL completa, parece realmente incorrecta.
Levi
2
De hecho, tuve que usar esto: CGI::parse(URI::parse(url).query)
portforwardpodcast
151

Me encontré necesitando lo mismo para un proyecto reciente. Basándose en la solución de Levi, aquí hay un método más limpio y rápido:

Rack::Utils.parse_nested_query 'param1=value1&param2=value2&param3=value3'
# => {"param1"=>"value1", "param2"=>"value2", "param3"=>"value3"}
Arthur Gunn
fuente
Mucho más ligero que burlarse de una solicitud de rack
Gareth
2
Buen descubrimiento. Si tiene parámetros simples (no anidados) y es sensible al rendimiento, Rack :: Utils.parse_query podría ser de interés. Vale la pena leer el código: github.com/rack/rack/blob/master/lib/rack/utils.rb
Levi
Gracias, es muy útil :)
Blue Smith
Esto funciona bien pero no funciona para casillas de verificación con el mismo nombre: param1=value1&param1=value2. El segundo valor triunfa sobre el primero.
B Seven
Para cualquiera que busque el inverso, es Rack::Utils.build_nested_query(params)(o Rack::Utils.build_query(params)si se analiza Rack::Utils.parse_query).
zelanix
99

Solo mejorado con la respuesta de Levi arriba:

Rack::Utils.parse_query URI("http://example.com?par=hello&par2=bye").query

Para una cadena como la URL anterior, devolverá

{ "par" => "hello", "par2" => "bye" } 
rtdp
fuente
77
gran respuesta. simple, procesa la URL completa como las preguntas de operación, y los valores del resultado son cadenas en lugar de matrices, como en las otras respuestas. Gracias.
jackocnr
3
Como comenté anteriormente, para cualquiera que busque lo contrario, es Rack::Utils.build_query(params).
zelanix
1
Cuidado: no todo lo contrario, al menos no en Ruby 1.8.7 / Rails 2.3. Una cadena de consulta de foo [] = 1 & foo [] = 2 se analiza correctamente como {"foo" => ["1", "2"]}, pero build_query lo convierte en "foo = 1 & foo = 2", que cuando se analiza nuevamente produce {"foo" => "2"}.
Raels
44

Para una solución Ruby pura, combínela URI.parsecon CGI.parse(esto puede usarse incluso si no se requieren Rails / Rack, etc.):

CGI.parse(URI.parse(url).query) 
# =>  {"name1" => ["value1"], "name2" => ["value1", "value2", ...] }
alup
fuente
33

Hay más de una forma de resolver su problema. Otros te han mostrado algunos trucos. Conozco otro truco. Aquí está mi intento: -

require 'uri'
url = "http://www.example.com/something?param1=value1&param2=value2&param3=value3"
uri = URI(url)
# => #<URI::HTTP:0x89e4898 URL:http://www.example.com/something?param1=value1&param2=value2&param3=value3>
URI::decode_www_form(uri.query).to_h # if you are in 2.1 or later version of Ruby
# => {"param1"=>"value1", "param2"=>"value2", "param3"=>"value3"}
Hash[URI::decode_www_form(uri.query)] # if you are below 2.1 version of Ruby
# => {"param1"=>"value1", "param2"=>"value2", "param3"=>"value3"}

Lea el método docomentation de ::decode_www_form.

Arup Rakshit
fuente
13

Eche un vistazo a la gema direccionable , un reemplazo popular para el módulo URI de Ruby que facilita el análisis de consultas:

require "addressable/uri"
uri = Addressable::URI.parse("http://www.example.com/something?param1=value1&param2=value2&param3=value3")
uri.query_values['param1']
=> 'value1'

(Al parecer, también maneja la codificación / decodificación de parámetros, a diferencia de URI)

Yarin
fuente
-3

En su controlador, debería poder acceder a un diccionario (hash) llamado params. Por lo tanto, si sabe cuáles son los nombres de cada parámetro de consulta, simplemente params[:param1]acceda a él ... Si no sabe cuáles son los nombres de los parámetros, puede recorrer el diccionario y obtener las claves.

Algunos ejemplos simples aquí .

kafuchau
fuente
OK, lo sabía, funciona bien en el controlador con la URL solicitada, pero ¿cómo hacer eso para otras URL arbitrarias?
Flackou