# ActiveRecord Mixing Conditions + Better Way to Write This

**URL:** <https://www.ruby-forum.com/t/activerecord-mixing-conditions-better-way-to-write-this/195739>\
**Category:** Ruby\
**Created:** [September 29, 2010, 11:25am UTC](https://www.ruby-forum.com/t/activerecord-mixing-conditions-better-way-to-write-this/195739 "2010-09-29T11:25:32Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![kingston](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e8c25b/32.png) [@kingston](https://www.ruby-forum.com/u/kingston)\
**Post date:** [September 29, 2010, 11:25am UTC](https://www.ruby-forum.com/t/activerecord-mixing-conditions-better-way-to-write-this/195739/1 "2010-09-29T11:25:32Z")

</div>

Is There A better Way to Write this

I have A Condition which previous Look Very clean and easy to understand  
like

Account.first.websites.last.users.find(:all,:conditions =\> {:country =\>  
“XYZ”,:status =\> “Single”,:admin =\> nil)

Now the big problem is that user with admin = false is not picked up

i.e i want all the users from a specific country,having status as  
“Single” and admin is either “nil”(Null in database) or “false”

I manage to get desired code but doesn’t seem to be happy with clarity  
of it

Account.first.websites.last.users.find(:all,:conditions =\> [“country = ?  
AND status = ? AND admin IS NULL OR admin = ?”,“XYZ”,“Single”,“false”])

Any Help would be appreciated

thanks

---

<div class="post-metadata">

**Author:** ![kingston](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e8c25b/32.png) [@kingston](https://www.ruby-forum.com/u/kingston)\
**Post date:** [September 29, 2010, 8:25pm UTC](https://www.ruby-forum.com/t/activerecord-mixing-conditions-better-way-to-write-this/195739/2 "2010-09-29T20:25:31Z")

</div>

On Wed, Sep 29, 2010 at 4:25 AM, Ken G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> ## i.e i want all the users from a specific country,having status as thanks
> 
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

Hi, this is a Ruby list, so it would be best to ask questions like this  
on a  
Rails list (looks like you’re posting from [ruby-forum.com](http://ruby-forum.com), you can  
access  
the Rails list from there too [http://www.ruby-forum.com/forum/3](http://www.ruby-forum.com/forum/3))

At [find (ActiveRecord::Base) - APIdock](http://apidock.com/rails/ActiveRecord/Base/find/class) they suggest  
doing

Project.all  
[http://apidock.com/rails/ActiveRecord/Base/all/class](http://apidock.com/rails/ActiveRecord/Base/all/class)(:conditions  
=\> “archived IS NULL OR archived = ‘f’”)

Which is pretty similar to what you’re trying to do, but its biggest  
shortcoming is that it doesn’t play well with other conditions. At one  
time  
I swore you could chain these together, but now they seem to return an  
Array  
instead of a lazy object (maybe I was thinking of DataMapper?) Anyway,  
to  
get around that issue, you can make it a named scope like this

class User \< ActiveRecord::Base  
named\_scope :not\_admin , lambda {{ :conditions =\> “admin IS NULL OR  
admin  
= ‘f’” }}  
end

This creates a method User.not\_admin that will start building a query  
(and  
execute it if you call just like this) you can then append to that query  
your other conditions. The lambda is just like a do … end block,  
except  
that it returns a reference to the object it creates, you can think of  
it  
exactly like a do end block, but you need to use curly braces on it  
because  
of how blocks bind of objects. So the first curly braces are for the  
block,  
the second are for the hash table we are returning.

This then lets you make queries like so:  
User.not\_admin  
User.not\_admin.all( :conditions =\> { :country =\>“XYZ” , :status =\>  
“Single”  
} )

As an alternative, you might set admin to be false by default (your  
migration would look like t.boolean :admin , :default =\> false ), and  
then  
validate that it is either true or false (in your class add  
validates\_inclusion\_of :admin, :in =\> [true, false]) Then you don’t have  
to  
deal with having two kinds of falses. Note that this will prevent the  
record  
from saving if it gets set to nil (it will default to false, though, so  
this  
can only happen if something explicitly sets it to nil).

---

<div class="post-metadata">

**Author:** ![kingston](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e8c25b/32.png) [@kingston](https://www.ruby-forum.com/u/kingston)\
**Post date:** [September 29, 2010, 9:13pm UTC](https://www.ruby-forum.com/t/activerecord-mixing-conditions-better-way-to-write-this/195739/3 "2010-09-29T21:13:04Z")

</div>

Ken G. wrote:

> I manage to get desired code but doesn’t seem to be happy with clarity  
> of it
> 
> Account.first.websites.last.users.find(:all,:conditions =\> [“country = ?  
> AND status = ? AND admin IS NULL OR admin = ?”,“XYZ”,“Single”,“false”])

Beware relative precedence of AND and OR. It’s possible AND binds more  
tightly than OR, I’m not sure. So to be safe:

[“country = ? AND status = ? AND (admin IS NULL or admin=?)”, …]

If you are using Rails 3, then look at the new syntax which Active  
Relation gives you. Google “rails 3 arel”
