Ruby: How to turn a hash into HTTP parameters?

后端 未结 14 1578
故里飘歌
故里飘歌 2020-12-07 06:46

That is pretty easy with a plain hash like

{:a => \"a\", :b => \"b\"} 

which would translate into

\"a=a&b=b\"
<         


        
相关标签:
14条回答
  • 2020-12-07 07:47
    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
    
    0 讨论(0)
  • 2020-12-07 07:49

    Here's a short and sweet one liner if you only need to support simple ASCII key/value query strings:

    hash = {"foo" => "bar", "fooz" => 123}
    # => {"foo"=>"bar", "fooz"=>123}
    query_string = hash.to_a.map { |x| "#{x[0]}=#{x[1]}" }.join("&")
    # => "foo=bar&fooz=123"
    
    0 讨论(0)
  • 2020-12-07 07:50

    For basic, non-nested hashes, Rails/ActiveSupport has 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

    0 讨论(0)
  • 2020-12-07 07:50

    I know this is an old question, but I just wanted to post this bit of code as I could not find a simple gem to do just this task for me.

    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
    

    Rolled up as gem here: https://github.com/simen/queryparams

    0 讨论(0)
  • 2020-12-07 07:52

    Update: This functionality was removed from the gem.

    Julien, your self-answer is a good one, and I've shameless borrowed from it, but it doesn't properly escape reserved characters, and there are a few other edge cases where it breaks down.

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

    The gem is 'addressable'

    gem install addressable
    
    0 讨论(0)
  • 2020-12-07 07:52

    No need to load up the bloated ActiveSupport or roll your own, you can use Rack::Utils.build_query and Rack::Utils.build_nested_query. Here's a blog post that gives a good example:

    require 'rack'
    
    Rack::Utils.build_query(
      authorization_token: "foo",
      access_level: "moderator",
      previous: "index"
    )
    
    # => "authorization_token=foo&access_level=moderator&previous=index"
    

    It even handles arrays:

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

    Or the more difficult nested stuff:

    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"}]}
    
    0 讨论(0)
提交回复
热议问题