Merging Params

Update : This article is now about reinventing the wheel and showing

Merging Params

by J on Feb 18, 2017

Update: This article is now about reinventing the wheel and showing you how easy it is to use the ruby language to accomplish your tasks. As robert pointed out in the comments, rails comes with the reverse merge method which you could call instead.

In this article, I'm going to show you how to have the params keep their state on your page in a very easy, concise manner. In most Rails pages you're only going to be changing the params for one object, possibly two. Conventionally, it's done like this:


<%= link_to 'Previous page', { :page => @post_pages.current.previous } %>

But that becomes a problem if you want to have anything other than the page variable in your query string. A solution to that:


<%= link_to 'Previous page', { :page => @post_pages.current.previous }.merge(params.reject{|k,v| k=="page"}) %>

Not so bad if you only have a couple of links. But I'm lazy and strive for minimalist code. Try throwing something like this in your application_helper

1
2
3
def params_merge(opts={})
  opts.merge(params.reject{|k,v| opts.keys.include?(k)})
end

And you can now do this:


<%= link_to 'Previous page', params_merge(:page => @post_pages.current.previous) %>

You might be working with a RESTful application, in which case you may have some routes that are defined like this:

1
2
3
4
5
6
map.with_options :controller => 'surf_reports', :action => 'worldwide' do |worldwide|
  worldwide.global_news     '/news',     :category => 'news'
  worldwide.global_events   '/events',   :category => 'events'  
  worldwide.global_latest   '/latest',   :category => 'latest'
  worldwide.global_location '/location', :category => 'location'
end

Now you know your route for global_news_path already has a category set. Let's say you want to link to that with seven other params. You can't just do global_news_path(params) because you might be in /events at the time, which already has the category set. Just like above, you could do something like this:


<%= link_to "News", global_news_path(params.reject{|k,v| k=="category"}) %>

But this quickly becomes tedious. Try this in your application_helper:

1
2
3
def params_without(name)
  params.reject{|k,v| k==name}
end

And now you can do an easy link_to:


<%= link_to "News", global_news_path(params_without :category) %>

Now you have some view code that's concise and pretty.


Update!
Duncan Beevers posted the following in the comments if you want something to work on all of your hashes. Thanks, Duncan!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Hash

  # lets through the keys in the argument
  # >> {:one => 1, :two => 2, :three => 3}.pass(:one)
  # => {:one=>1}
  def pass(*keys)
    tmp = self.clone
    tmp.delete_if {|k,v| ! keys.include?(k) }
    tmp
  end

  # blocks the keys in the arguments
  # >> {:one => 1, :two => 2, :three => 3}.block(:one)
  # => {:two=>2, :three=>3}
  def block(*keys)
    tmp = self.clone
    tmp.delete_if {|k,v| keys.include?(k) }
    tmp
  end

end

Tags: rails  | permalink


Comments

Leave a response

Duncan Beevers – February 19, 2017 @ 02:31 PM

A bit more versatile. class Hash # lets through the keys in the argument # >> {:one => 1, :two => 2, :three => 3}.pass(:one) # => {:one=>1} def pass(*keys) tmp = self.clone tmp.delete_if {|k,v| ! keys.include?(k) } tmp end # blocks the keys in the arguments # >> {:one => 1, :two => 2, :three => 3}.block(:one) # => {:two=>2, :three=>3} def block(*keys) tmp = self.clone tmp.delete_if {|k,v| keys.include?(k) } tmp end end


Peter Cooper – February 19, 2017 @ 04:59 PM

For the first example, wouldn’t this be better?

<%= link_to ‘Previous page’, :overwrite_params => { :page => @post_pages.current.previous } %>

I guess I might be missing something here, but I use overwrite_params all the time for this sort of thing.


robert – February 19, 2017 @ 04:59 PM

For the first case, that’s built into rails: I think for your second example it’d work too, since the right category is already in the hash and you’re trying to avoid overwriting it.


facets – February 20, 2017 @ 02:28 AM

what robert said, reverse_merge comes from the Ruby Facets (gem) project…

facets.rubyforge.org


edbond – February 20, 2017 @ 09:02 AM

Hi!

As Peter said, overwrite_params in url_for will help. If you want to remove parameter set value in hash to nil. <%= link_to ‘users’, :overwrite_params => {:tags=>nil, :page=>nil} %>


daniellibanori – March 16, 2017 @ 10:52 PM

def params_merge(opts={}) opts.merge(params.reject{|k,v| opts.keys.include?(k)}) end

or just

def params_merge(opts={}) params.clone.merge(opts) end


Sorry, comments are closed for this Post, but feel free to email us with your input. We'd love to hear it.

Blog Subscribe to RSS Feed SubscribeRSS
Podcast
RSS
Archive
   
Looking for Videos? FUNNY VIDEOS SPEAKING TUTORIALS
Tags
Contact Us

Like what you see? Contact us today to get the ball rolling on your next great idea.


Hosting by Rails Machine