I’ve implemented a simple search form (according to the “simple form” screencast) that searches the “illnesses” table in my DB.
Now I want the same search box to search both the “illnesses” table and the “symptoms” table.
My code currently looks like this:
main_page\index.html.erb:
<b>Illnesses</b>
<%= form_tag illnesses_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %><br/>
<%= submit_tag "Illnesses", :name => nil %><br/>
</p>
illnesses_controller.rb:
class IllnessesController < ApplicationController
def index
@illnesses = Illness.search(params[:search])
respond_to do |format|
format.html # index.html.erb
format.json { render json: @illnesses }
end
...
end
illness.rb:
class Illness < ActiveRecord::Base
...
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
Could you please guide me how to implement this extension?
I’m a beginner (obviously) and I don’t really know what should be the “form_tag” action, where should I implement it and which class should implement the extended search…
Thanks,
Li
Hmm, to just easily set off presuming you have a Symptom class similar to the Illness class(btw it would be most clean if you refactored the search functionality into a module and then include this module in both classes) then you can do:
But maybe you would like to refactor the name of the controller, because now it is not anymore Illness specific. Also notice that we are here using two search queries instead of one so it is not optimal, but saves you the pain of sending a pure SQL query for two types of models at the same time.
Okay for the module. If you are not familiar with modules they might seem a little weird but they are little more than a piece of code that can be shared across classes to keep things DRY which is our case too. You can imagine including the module as taking the code from the module and evaluating it (courtesy of interpreted languages) in the context of the class which has the same result as if the module code was hard coded into the class itself. So the module looks like:
And now any class, if it implements the find method(ActiveRecord API) can happily include this module and enjoy the search functionality like this:
That’s it. Now if you need to tweak your search code, you change it in one place and it propagates to all the includers. You can also create modules inside modules which is sometimes used like this:
But some of it is convention that is defined in ActiveSupport::Concern so not everything will probably work in pure ruby. I encourage you to experiment with these things, they make ruby real fun. Oh, extend is very much like include, only, as I understand it, it kind of evaluates on the class level. So all instance methods of the included module would become class methods of the includer module if you follow me. Have fun!