How to search in rails from two models?

How can i search my Rails database?

  • I'm so close to finishing my new database project, but I'm bumping up against my personal ceiling. Can anyone help me determine how to search my Rails project? Background Server Information: - Instant Rails 2.0 - Ruby 1.8.6 Patch Level 111 - Upgrades Rails to 2.0.2 - MySQL 5.0 - Ferret 0.11.6 - Acts As Ferret 0.4.3 I've got what I think is a simple database setup, but cannot figure out how to search the project. I've got my tables created, forms are accepting data, but I can't seem to search. This is the last piece of the project, so I'm itching for an answer. Any help would be greatly appreciated! I'll try to err on the side of 'too much' information. Tables: - Clients (ID, username, business_name, ... , Tradename_ID) - Tradenames (ID and title) - Words (ID, term, and Tradename_ID) Links: - Clients have a Tradename_ID - Words have a Tradename_ID Relations: - Each Client has a Tradename (has_one :tradenames) - Each Word has a Tradename (has_one :tradenames) - Each Tradename has many Clients (has_many :clients) - Each Tradename has many Words (has_many :clients) I would like to have a search box that searches the entire project. It should return results that meet any of the following criteria: - If the search term returns a Tradename, return all Clients with that Tradename ID - If the search term returns a Word, return all Clients with that linked Tradename ID - If the search term doesn't match a Tradename or Word, then search the Clients business_name for a match. If found, return any Clients with a matching business_name Currently, I've got another model called 'Community' that is acting as a hub for all the information. The current search model (from app\models\community.rb) looks like this: def search @title = "Search" if params[:q] query = params[:q] # First find the user hits... @clients = Client.find_by_contents(query, :limit => :all) # ...then the subhits. tradenames = Tradename.find_by_contents(query, :limit => :all) words = Word.find_by_contents(query, :limit => :all) # Now combine into one list of distinct users sorted by last name. hits = tradenames + words @clients.concat(hits.collect { |hit| hit.clients }).uniq! @clients = @clients.sort { |client| client.business_name } end endThis is the code that is doing the searching (in app\views\community\_search_form.rhtml):<% form_tag({ :action => "search", :controller => "community" }, :method => "get") do %><fieldset> <legend>Search</legend> <dl> <dt><label for="q">Search for:</label></dt> <dd><%= text_field_tag "q", params[:q] %></dd> </dl></fieldset><input id="submit" type="submit" value="Search" /><% end %>Any ideas? Should I be joining all of these into a single table? Some sort of recursive search? If so, how? (I'm Leia in the 'Help me Obi-Wan Kenobi, you're my only hope' analogy.)

  • Answer:

    Well, all that search code should be in a controller, probably the application controller since you want to search many models. Since you're using ferret and that's what it's for, make sure you've indexed all the fields you want to search in each model, then http://www.ruby-forum.com/topic/110364: @results = Client.find_by_contents("jemen", :models => :all) It should search across all the models you've added indexes on. Good luck!

jmevius at Ask.Metafilter.Com Visit the source

Was this solution helpful to you?

Other answers

Specifically, your problem is that the params hash isn't available inside of model classes.

voidcontext

Could you explain the 'indexed all fields' part? I've created something in app\models\client.rb (for example) called: acts_as_ferret :fields => ['business_name', 'screen_name'] Because I don't want to index things like the password. Is that what you mean by indexing? When I use the command (and look at my environment window), I see something that says: ENV["FERRET_USE_LOCAL_INDEX"] is nil, looks like we are not the server Will use local index. Any ideas?

jmevius

Yes, that's what I meant. That warning just means that ferret is using the local server instead of a DRb server. It's fine for your development box - just disregard it for now. You can also specify the models you want to search, instead of saying :all, you could say: @results = Client.find_by_contents("jemen", :models => [Client, Tradename, Word])

cdmwebs

Wow -- I think I'm really close. This is what I have as a search expression now: def search @title = "Search" if params[:q] query = params[:q] # First find the user hits... @results1 = Tradename.find_by_contents(query, :models => [Tradename, Client], :limit => :all) if @results1.empty? @results2 = Word.find_by_contents(query, :models => [Word, Tradename, Client], :limit => :all) if @results2.empty? @results = Client.find_by_contents(query, :models => [Client], :limit => :all) else @results = @results2 end else @results = @results1 end end endAnd it seems to be pulling the correct number of listings (querying all tables appropriately). Now, I'm just stuck on the display side of things. I have this sort of code for table display:<% if @results and not @results.empty? %><table class="database_dump"> <tr class="header"> <th class="name">Business Name</th> </tr> <% @results.each do |result| %> <tr class="<%= cycle('odd', 'even') %>"> <td class="name"><%= @results.id %></td> </tr> <% end %></table><% end %>It's giving me the proper *number* of results, but not the display I'm looking for. I can't figure out how to construct the term that says "for the results found in the query, give me the information from the clients table (specifically client.business_name, client.screen_name)". I'm so close! Thanks so far for all of the help.

jmevius

That's because you're trying to use the result set (@results) as the instance (result). It should look like this: http://pastie.caboo.se/203575

cdmwebs

Hmm, this is really close. In the three scenarios for search, this returns the correct values whenever the query matches the Clients table. If the correct match comes from Tradenames or Words, I get an error that says:undefined method `business_name' for #<Tradename id: 1, title: "Plumber"> or undefined method `business_name' for #<Word id: 3, tradename_id: 1, term: "pipe">This is returning the correct tradename_id for both queries (that is huge!). But, I'd like to return all results from Clients that have the same Tradename_id. I'm almost there!

jmevius

I might have to mock up a test, but I guess you could write an ugly case statement to see which model was returned and then use the proper field.case result when Client # client code here when Tradename # tradename code here when Word # word code hereendPlease note that this is bad form, but it will probably get you working until someone can help further or you figure it out.

cdmwebs

cdmwebs - I'm not completely sure about what the code above meant. My lack of knowledge on this one is massive, obviously. After playing with this thing after a late barbecue, I think I'm pretty close. Now, I've got the Search feeding into three blocks of code, depending on where the results come from. One block works -- it looks like this:<% if @results3 and not @results3.empty? %> <% @results.each do |result| %> <tr class="<%= cycle('odd', 'even') %>"> <td class="name"><%= result.business_name %></td> <td class="profile"><%= link_to result.screen_name, profile_url(:screen_name => result.screen_name) %></td> <td class="phone"><%= result.contact_phone %></td> <td class="zip"><%= result.address_zip %></td> </tr> <% end %><% end %>This block says, 'if the search term is found in Clients, return the following results'. It works great (I'm sure an actual Rails code expert would be horrified at the code that powers it). I've got another block that says 'if the search term is found in Tradenames, return the Tradename ID'. It looks like this:<% if @results1 and not @results1.empty? %> <% @results.each do |result| %> <tr class="<%= cycle('odd', 'even') %>"> <td class="name"><%= result.title %></td> <td class="profile"><%= result.id %></td> <td class="phone"> </td> <td class="zip"> </td> </tr> <% end %><% end %>What I would like it to do is another query. If a Tradename ID is returned (in result.id), then search the Clients table for all the clients that have the same Tradename ID. All of this code is stored in app\views\community\_client_table.rhtml Any ideas? This is the last step to finishing my demo -- I'm so close.

jmevius

Can you make a http://pastie.caboo.se/pastes/new of the entire view?

cdmwebs

Related Q & A:

Just Added Q & A:

Find solution

For every problem there is a solution! Proved by Solucija.

  • Got an issue and looking for advice?

  • Ask Solucija to search every corner of the Web for help.

  • Get workable solutions and helpful tips in a moment.

Just ask Solucija about an issue you face and immediately get a list of ready solutions, answers and tips from other Internet users. We always provide the most suitable and complete answer to your question at the top, along with a few good alternatives below.