# More dynamic way? Search Pagination

**URL:** <https://www.ruby-forum.com/t/more-dynamic-way-search-pagination/47761>\
**Category:** Rails\
**Created:** [November 12, 2005, 12:49pm UTC](https://www.ruby-forum.com/t/more-dynamic-way-search-pagination/47761 "2005-11-12T12:49:52Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![codeslush](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c57346/32.png) [@codeslush](https://www.ruby-forum.com/u/codeslush)\
**Post date:** [November 12, 2005, 12:49pm UTC](https://www.ruby-forum.com/t/more-dynamic-way-search-pagination/47761/1 "2005-11-12T12:49:52Z")

</div>

All,

I’m new to ruby and to rails! 🙂 This will give you all a chance to  
tear my code apart! Feel free to offer better techniques as necessary!

I have a need to implement somewhat dynamic search across several  
different entities.

In one of my controllers, I have an action called search. I have some  
code working to do a search based on parameters from a form submit.  
Now, I want to make the search routine available to all controllers.  
I’m trying to figure out if I can dynamically name variables in ruby or  
not based on input args to a function.

Here is the code I have in the controller:

@whereClause = “”  
@params[:price\_quote].each { | key, value |  
if value.length \> 0  
@whereClause = @whereClause.length == 0 ? “#{key} = #{value}” :  
@whereClause \<\< " and #{key} = #{value}"  
end  
}

if @whereClause.length \> 0 then  
@price\_quote\_pages, @price\_quotes = paginate :price\_quote,  
:per\_page =\> 10, :conditions =\> @whereClause  
else  
@price\_quote\_pages, @price\_quotes = paginate :price\_quote,  
:per\_page =\> 10  
end

I would like to have a function called “getSearchResults” or something  
similar where I pass in the name of the controller and the param hash.  
Based on the input args, it would find the proper hash and create the  
page objects with the controller name.

Any suggestions?

Michael

---

<div class="post-metadata">

**Author:** ![codeslush](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c57346/32.png) [@codeslush](https://www.ruby-forum.com/u/codeslush)\
**Post date:** [November 12, 2005, 12:49pm UTC](https://www.ruby-forum.com/t/more-dynamic-way-search-pagination/47761/2 "2005-11-12T12:49:55Z")

</div>

On Friday 11 November 2005 7:27 am, Michael wrote:

> I would like to have a function called “getSearchResults” or something  
> similar where I pass in the name of the controller and the param hash.  
> Based on the input args, it would find the proper hash and create the page  
> objects with the controller name.
> 
> Any suggestions?

Hi Michael,

I’m quite new to Rails myself, but I’ll try to help.

Start by putting a function in app/controllers/application.rb:

```
private

def dynamic_search(
	options = {
		:controller_name => "default_controller",
		:search_params => {}
	})
	controller_name = options[:controller_name]
	search_params = options[:search_params]

	# (your search code here)

end

```

Then in any of your app’s controllers you can call it using:

@results = dynamic\_search( :controller\_name =\>  
“some\_controller”, :search\_params =\> { :key1 =\> “value1”, :key2 =\>  
“value2”,  
etc})

Using this technique, you could omit either of the parameters passed to  
the  
function by replacing “default\_controller” with the name of, well, your  
default controller, and adding code to your search routine to handle the  
parameters. Here’s a hint:

```
for column in Price_quote.content_columns
	...
end

```

Will let you iterate through the column names of the db table.

Good luck. (The more experienced of you please correct me where I’m  
wrong)

---

<div class="post-metadata">

**Author:** ![codeslush](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c57346/32.png) [@codeslush](https://www.ruby-forum.com/u/codeslush)\
**Post date:** [November 12, 2005, 12:49pm UTC](https://www.ruby-forum.com/t/more-dynamic-way-search-pagination/47761/3 "2005-11-12T12:49:55Z")

</div>

Mark,

Thank you for the input.

I already have the column names and values to search on - they were in  
the params hash from my original sample. I get them when the user  
submits the search form.

@params[:price\_quote].each { | key, value | …

What I really would like to know how to do, though, is somehow  
dynamically name the objects. For example, If I tell the function that  
this is for the price\_quote controller, then I want it to create the  
proper pagination objects for me. Taking the sample from below, I want  
to be able to name “@price\_quote\_pages” based on the input of the  
function. It could be “@lead\_pages”, “@activity\_pages”, etc…

if @whereClause.length \> 0 then

@price\_quote\_pages, @price\_quotes = paginate :price\_quote, :per\_page =\>  
10, :conditions =\> @whereClause

…

The views rely on the name of these pagination objects to navigate  
forward and backward through the records.

All in all, this search actually sucks pretty badly! It isn’t flexible  
at all. I had a bug in my original post whereby I didn’t surround the  
param values with single quotes (worked great for numeric fields  
though)…hahaha. I just need something basic for simple search on  
multiple fields without having to hard code the names (e.g.  
ActiveRecord.find\_all\_by…and…and…) and get the results into a  
pagination object!

Thanks,

Michael

Mark B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:  
On Friday 11 November 2005 7:27 am, Michael wrote:

> I would like to have a function called “getSearchResults” or something  
> similar where I pass in the name of the controller and the param hash.  
> Based on the input args, it would find the proper hash and create the page  
> objects with the controller name.
> 
> Any suggestions?

Hi Michael,

I’m quite new to Rails myself, but I’ll try to help.

Start by putting a function in app/controllers/application.rb:

private

def dynamic\_search(  
options = {  
:controller\_name =\> “default\_controller”,  
:search\_params =\> {}  
})  
controller\_name = options[:controller\_name]  
search\_params = options[:search\_params]

# (your search code here)

end

Then in any of your app’s controllers you can call it using:

@results = dynamic\_search( :controller\_name =\>  
“some\_controller”, :search\_params =\> { :key1 =\> “value1”, :key2 =\>  
“value2”,  
etc})

Using this technique, you could omit either of the parameters passed to  
the  
function by replacing “default\_controller” with the name of, well, your  
default controller, and adding code to your search routine to handle the  
parameters. Here’s a hint:

for column in Price\_quote.content\_columns  
…  
end

Will let you iterate through the column names of the db table.

Good luck. (The more experienced of you please correct me where I’m  
wrong)

---

<div class="post-metadata">

**Author:** ![codeslush](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c57346/32.png) [@codeslush](https://www.ruby-forum.com/u/codeslush)\
**Post date:** [November 12, 2005, 12:49pm UTC](https://www.ruby-forum.com/t/more-dynamic-way-search-pagination/47761/4 "2005-11-12T12:49:55Z")

</div>

On Friday 11 November 2005 10:38 am, Michael wrote:

> What I really would like to know how to do, though, is somehow dynamically  
> name the objects. For example, If I tell the function that this is for the  
> price\_quote controller, then I want it to create the proper pagination  
> objects for me. Taking the sample from below, I want to be able to name  
> “@price\_quote\_pages” based on the input of the function. It could be  
> “@lead\_pages”, “@activity\_pages”, etc…

I don’t think the controller is determined by the paginator. I’m  
thinking that  
you can pass whatever controller you want to the links generated from  
the  
paginator in your view:

\<%= link\_to ‘Previous page’, {:controller =\> @whatever, :page =\>  
@price\_quote\_pages.current.previous, :search =\> @params[‘search’],  
:order\_by  
=\> @params[‘order\_by’], :order\_dir =\> @params[‘order\_dir’] } if  
@price\_quote\_pages.current.previous %\>

and

\<%= link\_to ‘Next page’, {:controller =\> @whatever, :page =\>  
@price\_quote\_pages.current.next, :search =\> @params[‘search’], :order\_by  
=\>  
@params[‘order\_by’], :order\_dir =\> @params[‘order\_dir’] } if  
@price\_quote\_pages.current.next %\>

Check out the docs for the link\_to helper:

[http://api.rubyonrails.com/classes/ActionView/Helpers/UrlHelper.html#M000325](http://api.rubyonrails.com/classes/ActionView/Helpers/UrlHelper.html#M000325)

link\_to probably defaults to the current controller unless told  
otherwise.

---

<div class="post-metadata">

**Author:** ![codeslush](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c57346/32.png) [@codeslush](https://www.ruby-forum.com/u/codeslush)\
**Post date:** [November 22, 2005, 6:34am UTC](https://www.ruby-forum.com/t/more-dynamic-way-search-pagination/47761/5 "2005-11-22T06:34:00Z")

</div>

Hi Michael,

I’m also fairly new to rails, and I have been looking at this same  
issue. With some help from the people on rubyonrails irc I put together  
the following in application.rb

def search  
conditions = “0”  
params.delete(“controller”) # is there a better way to extract  
these terms???  
params.delete(“action”)  
params.delete(“page”)  
params.each {|key, value| conditions+= " OR #{key} LIKE  
‘%#{value}%’" }  
@name = self.controller\_name()  
@item\_pages, @items = paginate @name.to\_sym, :per\_page =\> 5,  
:conditions =\> conditions  
@model = Kernel.const\_get(@name.camelize)  
render :layout =\> ‘mylayout’  
end

and then I drop the following into each view as search.rhtml

\<% for item in @items %\>

\<% for column in @model.content\_columns %\> \<%=h item.send(column.name) %\>  
\<%end%\> \<%= link\_to 'Show', :action =\> 'show', :id =\> item %\> \<%= link\_to 'Edit', :action =\> 'edit', :id =\> item %\> \<%= link\_to\_remote "Remove", :url=\>{ :controller=\>"items", :action=\>"destroy", :id=\>item}, :loading=\>"status('item#{item.id}')", :complete=\>"new Effect.Fade('item#{item.id}')" %\>
\<% end %\>

\<%= pagination\_links(@item\_pages, {:params=\>params}) %\>

and now every one of my controllers that has an associated model name  
(e.g. recipes\_controller and recipe) has search available, e.g.

[http://rails/recipes/search?title=trifle](http://rails/recipes/search?title=trifle)

I wonder if this meets all your needs.

CHEERS\> SAM

---

<div class="post-metadata">

**Author:** ![codeslush](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/c57346/32.png) [@codeslush](https://www.ruby-forum.com/u/codeslush)\
**Post date:** [November 22, 2005, 6:51pm UTC](https://www.ruby-forum.com/t/more-dynamic-way-search-pagination/47761/6 "2005-11-22T18:51:03Z")

</div>

On 11/21/05, Sam J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I’m also fairly new to rails, and I have been looking at this same  
> issue. With some help from the people on rubyonrails irc I put together  
> the following in application.rb

I really hope nobody on IRC actually told you to use the code below.  
While the method they gave you will work it has an obvious SQL  
injection vulnerability.

> :conditions =\> conditions  
> @model = Kernel.const\_get(@name.camelize)  
> render :layout =\> ‘mylayout’  
> end

You should not be trusting the data given in params. You should be  
checking key against a list of known good keys, and using ? as  
placeholders for values. Maybe something like:

def search  
valid\_keys = %w’foo bar baz’  
conditions = [‘0’]  
valid\_keys.each do |key|  
if params.include?(key)  
conditions[0] \<\< " OR #{key} LIKE ?"  
conditions \<\< “%#{params[key]}%”  
end  
end  
@name = self.controller\_name()  
@item\_pages, @items = paginate @name.to\_sym, :per\_page =\> 5,  
:conditions =\> conditions  
@model = Kernel.const\_get(@name.camelize)  
render :layout =\> ‘mylayout’  
end

That’s untested, but it shouldn’t be vulnerable.

You should never, ever, under any circumstances, trust data that is in  
params. You should be checking, filtering, and/or scrubbing all  
client data before using it in your SQL queries (protection against  
SQL injection) or displaying it on your page (protection against cross  
site scripting). Rails makes SQL injection protection easy, by  
submitting an array for conditions using ? as placeholders for  
variables. I haven’t read the AWDR book, but I’m guessing (hoping)  
there is a section on this.
