Rails: Opposite of Hash#to_param
You're looking for Rack::Utils.parse_nested_query(query)
, which will convert it back into a Hash
. You can get it by using this line:
require 'rack/utils'
Ruby: How to turn a hash into HTTP parameters?
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
Hash remove all except specific keys
Some other options:
h.select {|k,v| ["age", "address"].include?(k) }
Or you could do this:
class Hash
def select_keys(*args)
select {|k,v| args.include?(k) }
end
end
So you can now just say:
h.select_keys("age", "address")
Rails hashes with unknown keys and strong parameters
Your need is completely opposite of objective of strong parameter,
when we define strong parameter then basically we are going to whitelist the coming params.
and here in your case we exactly don't know the keys, so there is no need to put strong parameter check over there. that will solve your problem.
Params hash keys as symbols vs strings
In Rails, the params
hash is actually a HashWithIndifferentAccess
rather than a standard ruby Hash
object. This allows you to use either strings like 'action'
or symbols like :action
to access the contents.
You will get the same results regardless of what you use, but keep in mind this only works on HashWithIndifferentAccess
objects.
Rails what is the oppsite of the to_query method?
This is a duplicate of this questions: Just use:
Rack::Utils.parse_query(my_query_string)
In order to decode the line in your example, be sure to unescape the string first:
require 'rack'
my_string = 'fields%5B%5D=exhb_0&fields%5B%5D=exh0_1&fields%5B%5D=t_g_a&fields%5B%5D=hp_1&fields%5B%5D=s1&fields%5B%5D=overflade_0&railing%5B%5D=A-3&railing_m=0&type%5B%5D=ltrappa&wood%5B%5D=wood_6'
unescaped_string = URI.unescape(my_string)
# => "fields[]=exhb_0&fields[]=exh0_1&fields[]=t_g_a&fields[]=hp_1&fields[]=s1&fields[]=overflade_0&railing[]=A-3&railing_m=0&type[]=ltrappa&wood[]=wood_6"
params_hash = Rack::Utils.parse_query(unescaped_string)
# => {"fields[]"=>["exhb_0", "exh0_1", "t_g_a", "hp_1", "s1", "overflade_0"], "railing[]"=>"A-3", "railing_m"=>"0", "type[]"=>"ltrappa", "wood[]"=>"wood_6"}
Rails flat params to hash
Try this:
params.map { |k,v| [k.split('.').reverse,v] }.map { |keys,val| keys.inject(val) { |val, e| { e => val }} }.inject({}) { |hsh, h| hsh.deep_merge(h) }
It may not be the most optimal way, but - unless we're talking about millions of items in the cart - it still does the job faster than a single DB query.
For your sample params the result should be:
{"shopping-cart"=>{"items"=>{"item-1"=>{"item-name"=>"Item one", "item-description"=>"An item", "unit-price"=>{"currency"=>"GBP"}, "quantity"=>"1"}, "item-2"=>{"item-name"=>"Item two", "item-description"=>"Another item", "unit-price"=>{"currency"=>"GBP"}, "quantity"=>"3"}, "item-3"=>{"item-name"=>"Item three", "item-description"=>"Yet another item", "unit-price"=>{"currency"=>"GBP"}, "quantity"=>"2"}}}, "edit_url"=>"http://somerailsapp/store/buy", "_charset_"=>"UTF-8", "controller"=>"order", "action"=>"process"}
You may also use
k.split('.').reverse.map { |k| sanitize_key(k) }
where sanitize_key
gets rid of item-
prefix and/or changes the item number to integer.
Edit: I just noticed that the price goes missing - so you may want to add '.amount'
to the
keys ending with unit-price
. Somehow this cart hash is not sanely structured...
Enjoy!
Is there an opposite function of slice function in Ruby?
Use except:
a = {"foo" => 0, "bar" => 42, "baz" => 1024 }
a.except("foo")
# returns => {"bar" => 42, "baz" => 1024}
How to remove a key from Hash and get the remaining hash in Ruby/Rails?
Rails has an except/except! method that returns the hash with those keys removed. If you're already using Rails, there's no sense in creating your own version of this.
class Hash
# Returns a hash that includes everything but the given keys.
# hash = { a: true, b: false, c: nil}
# hash.except(:c) # => { a: true, b: false}
# hash # => { a: true, b: false, c: nil}
#
# This is useful for limiting a set of parameters to everything but a few known toggles:
# @person.update(params[:person].except(:admin))
def except(*keys)
dup.except!(*keys)
end
# Replaces the hash without the given keys.
# hash = { a: true, b: false, c: nil}
# hash.except!(:c) # => { a: true, b: false}
# hash # => { a: true, b: false }
def except!(*keys)
keys.each { |key| delete(key) }
self
end
end
Related Topics
Rails 3 Additional Session Configuration Options (Key, Expires_After, Secure)
Eager Loading: the Right Way to Do Things
How to Convert PDF Files to Images Using Rmagick and Ruby
How to Check If a Variable Is a Number or a String
Get Class Location from Class Object
Rails Link_To External Site, Url Is Attribute of User Table, Like: @Users.Website
Cannot Load Such File -- Readline (Loaderror) When Running Heroku Create --Stack Cedar
Form Submitted Twice, Due to :Remote=>True
Attr_Accessor Strongly Typed Ruby on Rails
How to Get a Date from a Week Number