# Not sure how to do this

**URL:** <https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466>\
**Category:** Rails\
**Created:** [July 2, 2009, 11:43pm UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466 "2009-07-02T23:43:29Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![jhaagmans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/bc8723/32.png) [@jhaagmans](https://www.ruby-forum.com/u/jhaagmans)\
**Post date:** [July 2, 2009, 11:43pm UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466/1 "2009-07-02T23:43:29Z")

</div>

In an app I’m working on, I want to have a filter in which you can  
specify certain attributes and click “filter” to activate an AJAX  
request and return a list of, say, machines that match with those  
attributes.

No I’m not sure how to build the controller.

If I would specify all the attributes, I would simply do:

def filter  
@machines = Machine.find(:all, :conditions =\> { :attr\_1 =\> params  
[:attr\_1], :attr\_2 … }  
end

But how would I do this if only some of the attributes are specified  
and the others are nil? Would I have to create @machines including all  
machines and have Rails do the rest of the work or is there a way to  
get find to do what I want?

---

<div class="post-metadata">

**Author:** ![jhaagmans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/bc8723/32.png) [@jhaagmans](https://www.ruby-forum.com/u/jhaagmans)\
**Post date:** [July 2, 2009, 11:56pm UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466/2 "2009-07-02T23:56:55Z")

</div>

Off the top of my head:  
class Machine \< ActiveRecord::Base  
# Define a list of acceptable params for filtering  
FILTERS = [:name, :code]

```
# Finds records by params
def self.filter_by_params(params)
  conditions = params.select { |key,val| 

```

FILTERS.include?(key.to\_sym)  
and val }  
all(:conditions =\> conditions)  
end  
end

class MachinesController \< ApplicationController  
def index  
# Where params is { :filter =\> { :name =\> ‘Pat’, :code =\> ‘123’ }}  
@machines = Machine.filter\_by\_params(params[:filter])  
end  
end

---

<div class="post-metadata">

**Author:** ![jhaagmans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/bc8723/32.png) [@jhaagmans](https://www.ruby-forum.com/u/jhaagmans)\
**Post date:** [July 3, 2009, 11:07am UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466/3 "2009-07-03T11:07:26Z")

</div>

Could you explain why the first part would go entirely into the  
Machine model?

---

<div class="post-metadata">

**Author:** ![jhaagmans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/bc8723/32.png) [@jhaagmans](https://www.ruby-forum.com/u/jhaagmans)\
**Post date:** [July 3, 2009, 10:52pm UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466/4 "2009-07-03T22:52:12Z")

</div>

> Could you explain why the first part would go entirely into the

Machine model?

Because it’s better to encapsulate  
model logic in the models (and custom finders are model logic).  
Controllers should only be responsible for receiving a request,  
calling the appropriate model methods,  
then returning a response.

- Pat

---

<div class="post-metadata">

**Author:** ![jhaagmans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/bc8723/32.png) [@jhaagmans](https://www.ruby-forum.com/u/jhaagmans)\
**Post date:** [July 4, 2009, 7:09pm UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466/5 "2009-07-04T19:09:20Z")

</div>

You could try building up a chain of scopes - see this post:

[http://groups.google.com/group/rubyonrails-talk/browse\_thread/thread/a7df6a8b9628bb4b/d6b738f83084ec91?lnk=gst&q=scoped#d6b738f83084ec91](http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/a7df6a8b9628bb4b/d6b738f83084ec91?lnk=gst&q=scoped#d6b738f83084ec91)

As noted there, you can avoid cluttering up your model by using  
‘scoped’ to create anonymous scopes.

So your example would look like:

# in the controller action

proxy = Machine  
[:attr1, :attr2, :attr3].each do { |k|  
proxy = proxy.scoped(:conditions =\> Hash[k, params[k]]) unless params  
[k].blank?  
}  
@machines = proxy.find(:all)

That last find can also be a paginate, have limits, sorts, etc.

–Matt J.

---

<div class="post-metadata">

**Author:** ![jhaagmans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/bc8723/32.png) [@jhaagmans](https://www.ruby-forum.com/u/jhaagmans)\
**Post date:** [July 5, 2009, 11:26am UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466/6 "2009-07-05T11:26:35Z")

</div>

Now that I read again, scoped won’t allow destroy\_all to get through,  
but I  
still stand by my point 🙂

---

<div class="post-metadata">

**Author:** ![jhaagmans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/bc8723/32.png) [@jhaagmans](https://www.ruby-forum.com/u/jhaagmans)\
**Post date:** [July 5, 2009, 11:15am UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466/7 "2009-07-05T11:15:28Z")

</div>

That works, though it’s definitely a good idea to sanitize which params  
can  
be used in such a manner. Otherwise, someone could send params like {  
:destroy\_all =\> true } or something, and then there goes your database.  
Pat

---

<div class="post-metadata">

**Author:** ![jhaagmans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/bc8723/32.png) [@jhaagmans](https://www.ruby-forum.com/u/jhaagmans)\
**Post date:** [July 5, 2009, 7:09pm UTC](https://www.ruby-forum.com/t/not-sure-how-to-do-this/171466/8 "2009-07-05T19:09:47Z")

</div>

On 3 jul, 22:43, Pat N. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> - Pat  
> Thank you, that’s very clear!

I’ve decided to try and go with this solution as this actually does  
what I inteded to do. I just had some trouble understanding why in  
most examples this piece of code is put into the controller and you  
don’t.
