model_auto_completer

Rails’ auto_complete integration is pretty nice for building search functionality, but for entry forms it all too often falls short.

Typically if I’m using an auto complete field in a form it’s because I want to link that record with an existing entry in another table, such as connecting an event with a location, or a book with a publisher, and that won’t work because the value obtained from the auto completion is the name of the linked entity, not its ID. I’ve tried various ways of managing that, either by overriding the standard methods or by adding some extra code in my model that will convert a name back into the associated model ID, but they all feel like hacks and I’d not had time to clean up the code and package anything as a plugin.

Thankfully Xavier Nora‘s already done it with the model_auto_completer plugin. The plugin provides a set of helper methods that will allow you to use auto completion, but have the ID of the record found stored as a hidden field in your form, making processing considerably easier.

Initially I had a problem using the plugin, and in fact found my rails application falling over because the plugin wasn’t getting the right name for the foreign key and since I have other fields that allow entry of a new location, rails couldn’t tell if a post with:

location[]=123&location[name]=My%20Location

should use the first location data or the later data.

Looking through the code I found that instead of using:

foreign_key  = real_object.class.reflect_on_association(association).options[:foreign_key]

to get the foreign key it should be using:

foreign_key = real_object.class.reflect_on_association(association).primary_key_name

Having submitted a patch, I was very pleased to hear over the weekend that the change has been integrated into the plugin so I can let piston update back to the official trunk. With that change in place, the plugin is a great way to make data entry much more convenient.

Tags: , , ,

3 comments

  1. Heya,

    I was working on exactly the same problem and I’ve found it very nice that you did already a solution as plugin.
    Thanks for you work!

    One problem remains:

    Your model_auto_complete_result doesn’t work correctly when creating an composed field in the model, which does not
    directly belong to a database field, e.g.:

    def full_address
    ([address0, address1, address2, postal_code, city].reject {|s| s.blank?}).join(‘, ‘)
    end

    In order to use the code, you have to replace …
    content_tag(“li”, (phrase ? highlight(entry[field], phrase) : h(entry[field])), :id => entry.id)
    to:
    content_tag(“li”, (phrase ? highlight(entry.field, phrase) : h(entry.field)), :id => entry.id)

    Notice the entry.field instead of entry[field] … Then the code works great.

  2. And, another addition: You need to use render :inline instead of render :partial ….

  3. Thanks for the feedback, but the plugin isn’t actually my creation. As I noted above, the plugin is by Xavier Nora and so you probably want to send feedback his way.