Forum: Ruby on Rails appending conditions in a model

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Mike C. (Guest)
on 2009-05-15 00:29
(Received via mailing list)
I have a Search Model which contains search data. It looks like this:

keywords:string
by_user:boolean
by_title:boolean
...

So basically what I want is, if one of the booleans is true it will
search that particular index. So if by_user is true and by_title is
true, it will search the database of stories by user and title. If
only by_user is true, then it will only search by user.

So here's what I'm planning in the Search Model:

def stories
find_stories
end

def find_stories
find(:all, :conditions => ??)
end

I'm confused has to how to make the conditions since it will have to
check which booleans are true and then append onto the conditions. How
would I do this?
Marnen L. (Guest)
on 2009-05-15 20:20
(Received via mailing list)
On May 14, 4:28 pm, Mike C <removed_email_address@domain.invalid> wrote:
> I have a Search Model which contains search data. It looks like this:
>
> keywords:string
> by_user:boolean
> by_title:boolean
[...]
> def find_stories
> find(:all, :conditions => ??)
> end
>
> I'm confused has to how to make the conditions since it will have to
> check which booleans are true and then append onto the conditions. How
> would I do this?

Remember, :conditions can take a hash, which means you can do what you
want if you get your head out of ActiveRecord for a minute and into
Ruby hash-munging. :)  So for example:

def find_stories(by_user = false, by_title = false)
  conditions = {}
  conditions[:user] = 'some criteria' if by_user
  conditions[:title] = 'more criteria' if by_title
  Story.find(:all, :conditions => conditions.merge(:any =>
'other', :options => 'you want')
end

Does that help?

Best,
--
Marnen Laibow-Koser
http://www.marnen.org
removed_email_address@domain.invalid
Mike C. (Guest)
on 2009-05-15 21:05
(Received via mailing list)
Yeah, that helps a lot. I actually realized that a little bit after
posting and looked it up on Google, but this confirms it. Thanks!
Matt J. (Guest)
on 2009-05-15 21:12
(Received via mailing list)
You can also use the :symbol interpolation support in conditions, to
get code that looks like this:

def self.find_stories # add parameters as needed
  conditions = ['1 = 1'] # default; find complains if conditions is
empty
  conditions << 'title LIKE :search' if by_title
  conditions << 'user LIKE :search' if by_user
  Story.find(:all, :conditions => [conditions.join(' AND '), {:search
=> "%#{keywords}%"}])
end

This simple example works for a single search term; extending it to
split keywords on spaces and combine terms with ' OR ' (or ' AND ',
depending on your interpretation of keywords) is fairly
straightforward.

If you're doing more complicated things in your searches, you might
also want to try using named scopes instead. Something like:

def self.find_stories
  proxy = Story
  proxy = proxy.search_by_title(keywords) if by_title
  proxy = proxy.search_by_user(keywords) if by_user
  proxy
end

...where the scopes are defined on Story thus:

class Story < AR::Base
  named_scope :search_by_title, lambda { |keywords| kws =
keywords.split(/ /); { :conditions => [kws.map { |k| 'title
LIKE ?' }.join(' AND '), *(kws.map { |k| "%#{k}%" })] } }

end

and so on for user, where you can now add options like :joins and/
or :include if user is defined on another table.

--Matt J.
Mike C. (Guest)
on 2009-05-15 23:51
(Received via mailing list)
Wow, thanks for that! I'm using thinking sphinx, but the same thing
applies, right?
This topic is locked and can not be replied to.