像这样简单的哈希就很容易
{:a => "a", :b => "b"}
这将转化为
"a=a&b=b"
但是您如何处理更复杂的东西
{:a => "a", :b => ["c", "d", "e"]}
应该翻译成
"a=a&b[0]=c&b[1]=d&b[2]=e"
甚至更糟的是,(该怎么做)类似以下内容:
{:a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}]
感谢您提供的帮助!
像这样简单的哈希就很容易
{:a => "a", :b => "b"}
这将转化为
"a=a&b=b"
但是您如何处理更复杂的东西
{:a => "a", :b => ["c", "d", "e"]}
应该翻译成
"a=a&b[0]=c&b[1]=d&b[2]=e"
甚至更糟的是,(该怎么做)类似以下内容:
{:a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}]
感谢您提供的帮助!
Answers:
更新:此功能已从gem中删除。
朱利安,您的自答是一个很好的答案,我从中无耻地借鉴了它,但是它不能正确地逃脱保留字符,并且在其他一些情况下,它很容易崩溃。
require "addressable/uri"
uri = Addressable::URI.new
uri.query_values = {:a => "a", :b => ["c", "d", "e"]}
uri.query
# => "a=a&b[0]=c&b[1]=d&b[2]=e"
uri.query_values = {:a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}]}
uri.query
# => "a=a&b[0][c]=c&b[0][d]=d&b[1][e]=e&b[1][f]=f"
uri.query_values = {:a => "a", :b => {:c => "c", :d => "d"}}
uri.query
# => "a=a&b[c]=c&b[d]=d"
uri.query_values = {:a => "a", :b => {:c => "c", :d => true}}
uri.query
# => "a=a&b[c]=c&b[d]"
uri.query_values = {:a => "a", :b => {:c => "c", :d => true}, :e => []}
uri.query
# => "a=a&b[c]=c&b[d]"
宝石是“ 可寻址的 ”
gem install addressable
query_values变量的输入。
对于基本的非嵌套哈希,Rails / ActiveSupport具有Object#to_query。
>> {:a => "a", :b => ["c", "d", "e"]}.to_query
=> "a=a&b%5B%5D=c&b%5B%5D=d&b%5B%5D=e"
>> CGI.unescape({:a => "a", :b => ["c", "d", "e"]}.to_query)
=> "a=a&b[]=c&b[]=d&b[]=e"
http://api.rubyonrails.org/classes/Object.html#method-i-to_query
require 'active_support/all'需要
to_query中不能正确处理nil值。{ a: nil, b: '1'}.to_query == "a=&b=1",但Rack和CGI都解析a=为一个空字符串,而不是nil。我不确定是否支持其他服务器,但是使用rails时,正确的查询字符串应为a&b=1。我认为Rails无法产生正确解析的查询字符串是错误的……
如果您使用的是Ruby 1.9.2或更高版本,URI.encode_www_form则不需要数组就可以使用。
例如(来自1.9.3中的Ruby文档):
URI.encode_www_form([["q", "ruby"], ["lang", "en"]])
#=> "q=ruby&lang=en"
URI.encode_www_form("q" => "ruby", "lang" => "en")
#=> "q=ruby&lang=en"
URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en")
#=> "q=ruby&q=perl&lang=en"
URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]])
#=> "q=ruby&q=perl&lang=en"
您会注意到,数组值未使用包含[]我们都已习惯于查询字符串的键名来设置。使用的规范encode_www_form符合HTML5 application/x-www-form-urlencoded数据定义。
{:c => "c", :d => true}似乎已被检查,因此以字符串形式发送。
ruby -ruri -e 'puts RUBY_VERSION; puts URI.encode_www_form({:a => "a", :b => {:c => "c", :d => true}, :e => []})' # outputs 2.0.0 a=a&b=%7B%3Ac%3D%3E%22c%22%2C+%3Ad%3D%3Etrue%7D&
Addressable::URIActiveSupport的结果Object#to_query。
无需加载the肿的ActiveSupport或自己滚动,可以使用Rack::Utils.build_query和Rack::Utils.build_nested_query。这是一个博客文章,提供了一个很好的例子:
require 'rack'
Rack::Utils.build_query(
authorization_token: "foo",
access_level: "moderator",
previous: "index"
)
# => "authorization_token=foo&access_level=moderator&previous=index"
它甚至处理数组:
Rack::Utils.build_query( {:a => "a", :b => ["c", "d", "e"]} )
# => "a=a&b=c&b=d&b=e"
Rack::Utils.parse_query _
# => {"a"=>"a", "b"=>["c", "d", "e"]}
或更难的嵌套内容:
Rack::Utils.build_nested_query( {:a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}] } )
# => "a=a&b[][c]=c&b[][d]=d&b[][e]=e&b[][f]=f"
Rack::Utils.parse_nested_query _
# => {"a"=>"a", "b"=>[{"c"=>"c", "d"=>"d", "e"=>"e", "f"=>"f"}]}
:b是由两个哈希组成的数组。您最终将:b得到一个更大的哈希数组。
require 'rack'?考虑到现在所有主要的Ruby Web框架都是基于Rack构建的,因此它必须存在。
to_query还可以合并两个数组(v4.2)。
从Merb窃取:
# File merb/core_ext/hash.rb, line 87
def to_params
params = ''
stack = []
each do |k, v|
if v.is_a?(Hash)
stack << [k,v]
else
params << "#{k}=#{v}&"
end
end
stack.each do |parent, hash|
hash.each do |k, v|
if v.is_a?(Hash)
stack << ["#{parent}[#{k}]", v]
else
params << "#{parent}[#{k}]=#{v}&"
end
end
end
params.chop! # trailing &
params
end
参见http://noobkit.com/show/ruby/gems/development/merb/hash/to_params.html
class Hash
def to_params
params = ''
stack = []
each do |k, v|
if v.is_a?(Hash)
stack << [k,v]
elsif v.is_a?(Array)
stack << [k,Hash.from_array(v)]
else
params << "#{k}=#{v}&"
end
end
stack.each do |parent, hash|
hash.each do |k, v|
if v.is_a?(Hash)
stack << ["#{parent}[#{k}]", v]
else
params << "#{parent}[#{k}]=#{v}&"
end
end
end
params.chop!
params
end
def self.from_array(array = [])
h = Hash.new
array.size.times do |t|
h[t] = array[t]
end
h
end
end
{:a=>"a", :b=>"b", :c=>"c"}.map{ |x,v| "#{x}=#{v}" }.reduce{|x,v| "#{x}&#{v}" }
"a=a&b=b&c=c"
这是另一种方式。对于简单的查询。
我知道这是一个老问题,但是我只是想发布这段代码,因为我找不到简单的gem可以为我完成这项任务。
module QueryParams
def self.encode(value, key = nil)
case value
when Hash then value.map { |k,v| encode(v, append_key(key,k)) }.join('&')
when Array then value.map { |v| encode(v, "#{key}[]") }.join('&')
when nil then ''
else
"#{key}=#{CGI.escape(value.to_s)}"
end
end
private
def self.append_key(root_key, key)
root_key.nil? ? key : "#{root_key}[#{key.to_s}]"
end
end
在此处汇总为gem:https://github.com/simen/queryparams
URI.escape != CGI.escape对于URL,您需要第一个。
CGI.escape("http://localhost/search?q=banana&limit=7") => "http%3A%2F%2Flocalhost%2Fsearch%3Fq%3Dbanana%26limit%3D7" URI.escape("http://localhost/search?q=banana&limit=7") => "http://localhost/search?q=banana&limit=7"
我喜欢使用这个宝石:
https://rubygems.org/gems/php_http_build_query
用法示例:
puts PHP.http_build_query({"a"=>"b","c"=>"d","e"=>[{"hello"=>"world","bah"=>"black"},{"hello"=>"world","bah"=>"black"}]})
# a=b&c=d&e%5B0%5D%5Bbah%5D=black&e%5B0%5D%5Bhello%5D=world&e%5B1%5D%5Bbah%5D=black&e%5B1%5D%5Bhello%5D=world
require 'uri'
class Hash
def to_query_hash(key)
reduce({}) do |h, (k, v)|
new_key = key.nil? ? k : "#{key}[#{k}]"
v = Hash[v.each_with_index.to_a.map(&:reverse)] if v.is_a?(Array)
if v.is_a?(Hash)
h.merge!(v.to_query_hash(new_key))
else
h[new_key] = v
end
h
end
end
def to_query(key = nil)
URI.encode_www_form(to_query_hash(key))
end
end
2.4.2 :019 > {:a => "a", :b => "b"}.to_query_hash(nil)
=> {:a=>"a", :b=>"b"}
2.4.2 :020 > {:a => "a", :b => "b"}.to_query
=> "a=a&b=b"
2.4.2 :021 > {:a => "a", :b => ["c", "d", "e"]}.to_query_hash(nil)
=> {:a=>"a", "b[0]"=>"c", "b[1]"=>"d", "b[2]"=>"e"}
2.4.2 :022 > {:a => "a", :b => ["c", "d", "e"]}.to_query
=> "a=a&b%5B0%5D=c&b%5B1%5D=d&b%5B2%5D=e"