Sunday, August 30, 2009

Overriding Rails Auto Complete Text Field

auto_complete is excellent ajaxified plugin for auto completion, but round-trip server request make it a little bit slow. I could not help myself to make it faster enough for real time data but I did override this to dig through data from distinct field instead of pre-built auto-completion method that does a direct SQL query on the field and view whatever  I wanted by overriding controller and view.
First you'll need to install the auto_complete plugin:
ruby script/plugin install auto_complete
or download it right from here and move to vender/plugin.
This will give you the "text_field_with_auto_complete" view helper method amongst others and a controller hook "auto_complete_for" to implement the auto-complete action/method in your controller as per the auto_complete README, it looks like:
class BlogController < ApplicationController
   auto_compelere_for :post, :title
It would implement a auto_complete_for_post_title method in your controller class. The parameters are the object and field/method of that object. The method(auto_complete_for_post_title) it implements will dig through all the Post records in your database and do a LIKE comparison on the title column, comparing the title to the contents of the post[title] form field. With the results, it will generate the HTML for an unordered list (ul), and return that to the view. Now you can have this line in your view to be done for single field
<%= text_field_with_auto_complete :post, :title %>
Now Its time to play as we want and its as simple as that. Simply implement(override) the method and view according to you. Example: Controller
def auto_complete_for_post_title
   t = params[:post][:title]
   @results = Post.find_by_sql(:all, 
    :select => ', m.col1, p.col2, p.col3...', :from => 'posts p', 
     :joins => 'LEFT JOIN other o ON p.something = o.something',
    :conditions => ["p.something in (?) AND p.something = 1 AND LOWER(title) LIKE ?", some_array, '%' + v + '%'],
    :order => 'col1,col2,...')
   render :partial => '/common/autocomplete_post_title'
Since I needed same text field on different page, hence I just thrust it into application.rb to avail it anywhere, otherwise you need to put it in appropriate controller. Example: View - common/autocomplete_post_title.rthml
<ul id="something">
   <% for result @results do -%>
      <li id="<%= result.something%>">
       <%= result.something -%>
          <%= result.something %>
    <% end -%>
Tweak it in whatever way... To override in-built plugin's CSS, add {:skip_style => true} as below
<%= text_field_with_auto_complete :post, :title, { :class=>"input", :name => 'something', :value=>"something", :title=>"something", :onclick =>"DoSomething(this);", :onblur =>"DoSomething(this);" }, { :skip_style => true } %>