Como extrair parâmetros de URL de um URL com Ruby ou Rails?

137

Eu tenho alguns URLs, como

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

e gostaria de extrair os parâmetros desses URLs e obtê-los em um Hash. Obviamente, eu poderia usar expressões regulares, mas estava me perguntando se havia maneiras mais fáceis de fazer isso com Ruby ou Rails. Não encontrei nada no módulo Ruby, URImas talvez tenha perdido alguma coisa.

Na verdade, preciso de um método que faça isso:

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

Você gostaria de receber alguns conselhos?

Flackou
fonte
1
Hash[*string.split('&').collect{|i|i.split('=')}.flatten] Isso também funcionaria, mas é provavelmente a pior opção para este caso. Mas você ainda pode achar interessante esse trecho. (Publicando como comentário, já que eu não considero isso uma resposta :-))
Vojto

Respostas:

162

Eu acho que você deseja transformar qualquer string de URL em HASH?

Você pode tentar http://www.ruby-doc.org/stdlib/libdoc/cgi/rdoc/classes/CGI.html#M000075

require 'cgi'

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

retorna

{"param1"=>["value1"], "param2"=>["value2"], "param3"=>["value3"]}
Atirador de elite
fonte
1
OK, foi esse que eu perdi! É perfeito quando usado com URI.parse: CGI.parse (URI.parse (" example.com/... ) retorna o Hash desejado Obrigado por sua ajuda..
Flackou
91
Para maior clareza, @Flackou quer isto: CGI.parse(URI.parse(url).query)
Glenn Jackman
Não testei isso, mas a primeira chave listada, contendo o URL completo, parece realmente errada.
Levi
2
Eu realmente tive que usar isto: CGI::parse(URI::parse(url).query)
portforwardpodcast
151

Eu me vi precisando da mesma coisa para um projeto recente. Com base na solução da Levi, aqui está um método mais limpo e rápido:

Rack::Utils.parse_nested_query 'param1=value1&param2=value2&param3=value3'
# => {"param1"=>"value1", "param2"=>"value2", "param3"=>"value3"}
Arthur Gunn
fonte
Muito mais leve do que zombando de um pedido cremalheira
Gareth
2
Boa descoberta. Se você possui parâmetros simples (não aninhados) e é sensível ao desempenho, o Rack :: Utils.parse_query pode ser interessante. Vale a pena ler o código: github.com/rack/rack/blob/master/lib/rack/utils.rb
Levi
Obrigado, é muito útil :)
Blue Smith
Isso funciona bem, mas não funciona para caixas com o mesmo nome: param1=value1&param1=value2. O segundo valor supera o primeiro.
B Seven
Para quem procura o inverso, é Rack::Utils.build_nested_query(params)(ou Rack::Utils.build_query(params)se analisado Rack::Utils.parse_query).
Zelanix
99

Apenas melhorado com a resposta Levi acima -

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

Para uma string como a URL acima, ela retornará

{ "par" => "hello", "par2" => "bye" } 
rtdp
fonte
7
Ótima resposta. simple, processa a URL completa como o op pede, e os valores do resultado são strings em vez de matrizes, como nas outras respostas. obrigado.
jackocnr
3
Como comentei acima, para quem procura o inverso, é Rack::Utils.build_query(params).
Zelanix
1
Cuidado - não exatamente o inverso, pelo menos não no Ruby 1.8.7 / Rails 2.3. Uma string de consulta foo [] = 1 & foo [] = 2 é analisada corretamente como {"foo" => ["1", "2"]}, mas o build_query transforma isso em "foo = 1 & foo = 2", que quando analisado novamente produz {"foo" => "2"}.
Raels 20/07/16
44

Para uma solução Ruby pura, combine URI.parsecom CGI.parse(isso pode ser usado mesmo que Rails / Rack etc. não sejam necessários):

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

Existem mais de uma maneira de resolver seu problema. Outros mostrou alguns truques. Eu conheço outro truque. Aqui está a minha tentativa: -

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"}

Leia a documentação do método ::decode_www_form.

Arup Rakshit
fonte
13

Confira a gema endereçável - um substituto popular para o módulo URI do Ruby que facilita a análise 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'

(Ele também aparentemente lida com param codificação / decodificação, ao contrário do URI)

Yarin
fonte
-3

No seu Controller, você poderá acessar um dicionário (hash) chamado params. Então, se você sabe quais são os nomes de cada parâmetro de consulta, basta fazerparams[:param1] acessá-lo ... Se você não souber quais são os nomes dos parâmetros, poderá percorrer o dicionário e obter as chaves.

Alguns exemplos simples aqui .

kafuchau
fonte
OK, eu sabia disso, funciona bem no controlador com a URL solicitada, mas como fazer isso para outras URLs arbitrárias?
Flackou 23/03/10