ActiveRecord Mixing Conditions + Better Way to Write This

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

On Wed, Sep 29, 2010 at 4:25 AM, Ken G. [email protected]
wrote:

i.e i want all the users from a specific country,having status as
thanks

Posted via 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, you can
access
the Rails list from there too http://www.ruby-forum.com/forum/3)

At find (ActiveRecord::Base) - APIdock they suggest
doing

Project.all
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).

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”