太極者無極而生 太極者無極而生 - 6 months ago 31
Ruby Question

In Ruby or Rails, hash.merge({:order => 'asc'}) can return a new hash with a new key. What can return a new hash with a deleted key?

In Ruby (or Rails), we can do

new_params = params.merge({:order => 'asc'})


and now
new_params
is a hash with an added key
:order
.

But is there a line there can return the hash with a deleted key? The line

new_params = params.delete(:order)


won't work because the
delete
method returns the value and that's it. Do we have to do it in 3 steps?

tmp_params = params
tmp_params.delete(:order)
return tmp_params


Is there a better way? Because I want to do a

new_params = (params[:order].blank? || params[:order] == 'desc') ?
params.merge({:order => 'asc') :
(foo = params; foo.delete(:order); foo) # return foo


but the last line above is somewhat clumsy. Is there a better way to do it?

(note: because the default order is 'desc', so when there is no
order
param, that means it is the default and is
desc
, then toggle it to add
order=asc
, but otherwise, just remove the param
order
so that it is back to the default order of
desc
)

Answer

ActiveSupport adds a Hash#except method:

h1 = { a: 1, b: 2, c: 3 }
h1.except(:a) #=> {:b=>2, :c=>3}

A more complicated example:

h1 = { a:1, b: 2, c: 3 }
h2 = { b: 3, d: 5 }
h1.merge(h2).except(*h1.keys-h2.keys) #=> {:b=>3, :d=>5}

This will update keys that are present in h1 with the ones in h2, add the new ones from h2 and remove the ones that are in h1 but not in h2.