Topic: Controller design: REST and search

So I'm building an app and trying as much as possible to conform to the REST/resource structure. One problem: where do I put the search?

I can think of two approaches here:
1. Use the list/index action, with a querystring parameter to help filter down the list. So a sample URL would be like http://example.com/posts/?query=test+query. This keeps the REST/CRUD action structure intact and allows me to reuse the list/index view if I want, but may limit customization later on.

Some sample code for this approach (using acts_as_ferret)

class PostsController < ApplicationController
  def index
    @posts = (params[:query].blank?) Post.find(:all) : Post.find_by_contents(params[:query])
  end
end

2.  Use a separate search action. Allows for a completely different action/view combo which might be helpful if I want to customize later, but seems to break the REST/CRUD structure. sample code:
class PostsController < ApplicationController
  def index
    @posts = Post.find(:all)
  end

  def search
    @posts = Post.find_by_contents(params[:query])
  end
end


Given the two options, which is "best" in this case? I see upsides and downsides to both.

vinnie - rails forum admin

Re: Controller design: REST and search

I just thought of a third option: a dedicated SearchController. This one seems like a good possibility...

vinnie - rails forum admin

Re: Controller design: REST and search

You can even go one step further and have a dedicated Search model. Then the search controller is RESTful. This works well for advanced searches where there are too many fields to pass around in the URL, this way you can store the search fields in the database and just reference the id. You can also easily give the search a name and save it to a user's account. This is like a smart filter that they can just click on.

Of course the database can get large fast, so you would probably want a cron job of some kind to clean it up regularly.

If the search is simple, the first approach you mentioned is the one I recommend.

Railscasts - Free Ruby on Rails Screencasts

Re: Controller design: REST and search

Vin,
Could you put a little more 'meat on the bones' of that first example? I too, am trying to figure out how I'm going to provide various search functions for my users while using a RESTful approach. I nest four levels down and like how it speeds handling these tasks, but am terrified of the UNKNOWN!
Thanks,
David

Re: Controller design: REST and search

I am successfully using acts_as_ferret along with a Search Model and Controller. Here is a glimpse of what I have going on.

class Search
  attr_accessor :query   
 
  def initialize(query)
    @query = query   
  end
 
  def do_search
    return Term.multi_search(query, [Article, Term], :limit => 200)
  end 
end

class SearchesController < ApplicationController   
  def search                     
    search = Search.new(params[:query])
    @results = search.do_search
    @total = @results.size
  end   
end


I'm not sure how RESTful this really is, but 90% of my app is RESTian and this is working really well so far.

Re: Controller design: REST and search

pimpmaster wrote:

I am successfully using acts_as_ferret along with a Search Model and Controller. Here is a glimpse of what I have going on.

class Search
  attr_accessor :query   
 
  def initialize(query)
    @query = query   
  end
 
  def do_search
    return Term.multi_search(query, [Article, Term], :limit => 200)
  end 
end

class SearchesController < ApplicationController   
  def search                     
    search = Search.new(params[:query])
    @results = search.do_search
    @total = @results.size
  end   
end


I'm not sure how RESTful this really is, but 90% of my app is RESTian and this is working really well so far.

That's pretty good - but I think for it to be 100% restful the search action has to be a "new" action. REST controllers should only have the 7 verbs at the most. (depends how anal you want to get).

I think it makes sense to use new instead of search anyway /search/new

Or you could always change the route location for it.

http://danielfischer.com - Personal Web-Technology-Blog, Los Angeles.

Re: Controller design: REST and search

Pimpmaster, I read on pg. 213 of 'Rails Cookbook' how to route to a 'search' action using RESTful Rails. So that's good, I know how to call the action using this routing approach.
I assume your 'class' declaration is in the table model.rb file? Where did you get that "Term.multi_search(method)? Is this something that comes in the Acts_as_Ferret plugin?
Then you show a controller action called 'search'. Can you give me a clue as to what the view looks like that establishes these (params[:query]).
I don't want to be a 'taker' here...if there's something I can help you with please let me know? I'm going to be 'whipping out' many business type applications in the future.
David
dak AT itracker DOT com

Re: Controller design: REST and search

You are correct about multi_search, it is a method within acts_as_ferret. As you may have guessed this particular method is used to search across multiple models.

As for the view, here is my search input. Pretty basic stuff..

<% form_tag(:controller => 'searches' , :action => 'search') do %>
<%= text_field_tag 'query' %>
<%= submit_tag "search" %>
<% end %>

Here is the view code for my search results:

<% @results.each do |result| %>
<div class="result">   
<%- case result
   when Term -%>
    <h2><%= link_to result.title, term_path(result) %></h2>       
    <small>Filed under: <strong>Glossary Terms</strong></small>       
    <%= excerpt(result.body,25) %>   
<%- when Article -%>
    <h2><%= link_to result.title, article_path(result) %></h2>
        <small>Filed under: <strong>Articles</strong></small>
    <%= excerpt(result.body,25) %>   
<%- end -%>

Notice how I use a case statement to handle different models in the results. This wont be necessary if you are just searching one model.

For more info on that nifty excerpt method, check out this thread

If you do decide to go with acts_as_ferret, peep this extensive tutorial to get started.

Jens Kraemer, the creator of acts_as_ferret is very good about answering even the most noobish questions. You can post to the official mailing list via the Ruby Forum

Search (especially multi) is definitely not the easiest thing to get going. Be prepared to juggle quite a bit of code before things are working the way you want.

Last edited by pimpmaster (2007-05-09 19:47:26)

Re: Controller design: REST and search

DFischer wrote:

I think for it to be 100% restful the search action has to be a "new" action. REST controllers should only have the 7 verbs at the most.

I though about it, but FWIW, I am only using REST where I think it really makes sense, particularly for CRUD and delivering fast and easy formats with respond_to blocks. Since I didn't need CRUD or XML for search I just punted on REST for this one... I suppose the consistency of the URLs are nice, but I almost prefer www.site.com/search , which is how I configured my route.

Matter of preference I suppose.. or anal retentiveness,as you put it tongue

Last edited by pimpmaster (2007-05-09 19:54:54)

Re: Controller design: REST and search

From what I can see on your input view, you're counting on the user to have intimate knowledge in SQL to write the query string?
<%= text_field_tag 'query' %>
Or do you somehow grab all your users' query requests and write them to one string called "query"?
Did the @results pointer come from the controller.search.action? What does a 'result' object look like?
Thanks for the information.
David

Re: Controller design: REST and search

BraveDave wrote:

From what I can see on your input view, you're counting on the user to have intimate knowledge in SQL to write the query string?
<%= text_field_tag 'query' %>
Or do you somehow grab all your users' query requests and write them to one string called "query"?
Did the @results pointer come from the controller.search.action? What does a 'result' object look like?
Thanks for the information.
David

'query' is just what routes to the acts_as_ferret plugin which will search all the models you specify with that 'query'.

http://danielfischer.com - Personal Web-Technology-Blog, Los Angeles.

Re: Controller design: REST and search

query is just a symbol that Rails passes around internally. The user always enters plain text.

But you do raise an interesting point, someone could inject SQL commands in these fields. See Ryan's Railscast on this very subject:

http://www.railscasts.com/episodes/25

I am looking  into securing my search code, but so far from what I can see, there is not much danger here because the Search model is not backed by a database table. Ferret processes its queries off a generated index file.

Re: Controller design: REST and search

I just finished reading the Acts_as_Ferret documentation and it only talks about creating an index on top of your data model that is then accessible and maintainable. I don't know why you guys are preaching this for creating query reports/lists?

Daniel you write "'query' is just what routes to the acts_as_ferret plugin which will search all the models you specify with that 'query "

Jack, you write "The user always enters plain text". Where do they enter plain text?

Well, NOWHERE does anyone talk about how the user loads up this 'query' information and there are NO examples of what the controller looks like or a view. I don't know where you guys' get this advice?? Where do you find your "extensive tutorial"?
I feel like I took one step forward and two back.

Re: Controller design: REST and search

I don't know why you guys are preaching this for creating query reports/lists?

You are free to explore other options, but I can say that after weeks of research, trial and error, I settled on this solution. Have a look at some of the alternatives if you like.. most of these projects are also sorely lacking on solid tutorials/docs.. hopefully that will change in the future...

"The user always enters plain text". Where do they enter plain text?

See post #8, The first code example generates the input field in which the user enters their searches. I have it sitting in a partial file that I render on my master layouts. You wont find any of this in the documentation... the developers assume you already know how to do it, though they will help if you ask nicely smile

Where do you find your "extensive tutorial"? I feel like I took one step forward and two back.

LOL.. I feel your pain dude. A lot of these plugins are aimed at more proficient programmers. It took me two weeks of intense coding (and lots of cursing under my breath) before I got it right.

I've posted most of my code as a blueprint for you, but every app is different so it will take you time to learn how to bend the code to meet your needs. The best advice I can give is to work on this in phases... each time you hit a wall (and you will) just take a step back, post your problem here or onthe official acts_as_ferret forum, and work on something else in your app. Pick your battles and don't fall into the trap of obsessing over problems you are not yet equipped to solve.

It also really helps to write a list of the type of behavior you want to creat.