1 Jul 2007, 6:35pm

by Ariejan de Vroom

ActiveScaffold + acts_as_taggable + Auto Complete

I’ve talked before on how to use ActiveScaffold with acts_as_taggable_on_steroids.

The problem with that solution was that, although the checkboxes for every tag are very nice, you couldn’t easily add new tags. For some people, this may be fine, for others, it is not.

Together with a colleague (who wishes not to be named), I found a solution that is quite elegant. Instead of using check boxes, and creating all kinds of subforms in ActiveScaffold, we opted for an auto_completing, comma-separated list of tags.

This article descripes the solution we found. I think you’ll like it very much!

When you try to use acts_as_taggable with ActiveScaffold, you might use something like this in your BooksController.

active_scaffold :books do |config|
   config.columns = [:title, :body, :tags]
   config.list.columns = [:title, :tag_list]
   config.columns[:tags].ui_type = :select
   # ...
end

This is not so useful when you want the flexibility of creating new tags instantly. Therefore, it’s better to use the tag_list:

active_scaffold :books do |config|
   config.columns = [:title, :body, :tag_list]
   config.list.columns = [:title, :tag_list]
   # ...
end

You get a text_field for writing down the tags (comma-separated). The problem of this is that the user has to keep all the tags in mind and is not allowed to make any typos in the tag. To help our users out, I use Rails’ auto_complete feature.

In your BooksController:

auto_complete_for :book, :tag_list
 
def autocomplete_tag_list
  @all_tags = Tag.find(:all, :order => 'name ASC')
 
  re = Regexp.new("^#{params[:record][:tag_list]}", "i")
  @tags = @all_tags.find_all do |t|
    t.name.match re
  end
 
  render :layout => false
end

We can now create the template for the results which are found.
In app/views/books/autocomplete_tag_list.rhtml:

<ul class="autocomplete_list">
<% @tags.each do |t| %>
<li class="autocomplete_item"><%= t %></li>
<% end %></ul>

Now comes the difficult part, integration of the auto_complete widget within ActiveScaffold.

ActiveScaffold has the possibility to change the way every attribute is displayed on the create and edit page. I want to change the form for the attribute ‘tag_list’. To do this, I create create a file named app/views/books/_tag_list_form_column.rhtml:

<dl>
<dt>
   <label for="record_tag_list">AutoCompleted Tag List</label>
 </dt>
<dd>
   <%= text_field_tag 'record[tag_list]', @record.tag_list %>
<p class="auto_complete" id="record_tag_list_<%=@record[:id]%>_auto_complete">
        style="{height: 80px;}">
 
<script type="text/javascript">
    //<![CDATA[
    var record_tag_list_<%= @record[:id].to_s %>_auto_completer =
     new Ajax.Autocompleter(
       \'record[tag_list]\',
       \'record_tag_list_<%=@record[:id]%>_auto_complete\',
       \'/articles/autocomplete_tag_list\', {tokens: \',\'});
    //]]>
   </script>
 </dd>
</dl>

This shows a text field and generates a div that contains the available tags that we can show to the user. To populate the list of tags we use Ajax.Autocompler, which requires three arguments: the id of the text_field; the id of the div where you want to show possible tags to the user; and third, the URL of the action we created before, that returns the proper tags.

The ‘tokens’ part of the last argument indicates that the user can seperate multiple tags with a comma. So, if you’ve entered one tag, added a comma and start typing a new tag, the auto complete feature will only lookup that second tag you’re typing!

That’s it. Just spice things up a bit with some Style, and you’re done. Enjoy!

Please share the love of this post by bookmarking it, and sharing it with others. Thanks!

  • Digg
  • del.icio.us
  • description
  • Reddit
  • Technorati
  • BlinkList
  • E-mail this story to a friend!
  • Facebook
  • Live
  • MisterWong
  • Netvouz
  • NewsVine
  • Slashdot
  • SphereIt

[...] ActiveScaffold + acts_as_taggable + Auto Complete [...]

2 Jul 2007, 10:08am
by Guillaume


It seems to work great, thanks for that work !

2 Jul 2007, 12:24pm
by Ariejan


Well, please digg the story, then. ;) Thanks.

2 Jul 2007, 11:48pm
by Guillaume


done :)

30 Jul 2007, 10:20pm
by Anthony Topper


This is nifty. One, how do we speed it up? Two, how can we make it behave more like when you tag a page with del.icio.us?

4 Sep 2007, 4:09am
by Peter


This is a great tutorial. My only suggestion would be to change the autocomplete to do the string matching in sql as follows:

def autocomplete_tag_list
@tags = Tag.find(
:all,
:order => “name ASC”
:conditions => ["name LIKE ?", "#{params[:record][:tag_list]}%”]
)
render :layout => false
end

24 Sep 2007, 9:34pm
by Shannon


Nice - This is exactly what I was looking for!

I’ll implement this after lunch…

:)

14 Oct 2007, 7:11pm
by Guillaume


Hi,

I ve got a very nice “bug” using Acts as taggeable and Active Scaffold.. let me explain very fast..

I ve got 2 models (categ and souscateg), which all use acts_as_taggeable… these to models are linked together :

categ has many souscateg
souscateg belongs_to categ

In ActiveScaffold configuration for both model i include the other model..
for example for souscateg controller, i ve :
config.columns = [:tag_list, ****, :categ]..

With that, when i edit a tag list, it s the mess, because ActiveScaffold doesn t understand to which tag_list it refers…

In log it s possible to find out :

ActionView::TemplateError (undefined method `tag_list’ for #) on line #6 of app/views/souscateg/_tag_list_form_column.rhtml:

(because of the inclusion, tag_list is loaded both for souscateg and categ, and it seems to be a big problem there)

If i exclude :categ from ActiveSaccold souscateg controller configuration, it works well…. but unfortunately i need it…

Do you have any idea of how to resolve that problem ?
thx a lot

Guillaume.

4 Jul 2008, 1:44am
by GG Crew


The “tokens” piece is exactly what I was looking for! I am a tad surprised that this hasn’t been incorporated into the auto_complete plugin.

Thanks!

*name

*e-mail

web site

leave a comment