ActiveScaffold, Acts_as_taggable_on_steroids

11 June 2007

Update: also read Active Scaffold + Acts_as_taggable + Auto Completion.

This is kind of an advanced topic, but I think it may be useful to a lot of people.

ActiveScaffold is a great plugin to start building a user interface. The great thing about AS is, that is automatically recognizes associated models. When editing a model, you can easily add or select another model that you want to associate with is.

The best example of this is an Article, where you can select the author (the associated User model) with a drop down box.

There is only one point where I ran into trouble with ActiveScaffold: acts_as_taggable_on_steroids.

Acts_as_taggable_on_steroids allows you to easily attach tags to models and do all kinds of crazy stuff with them. But, if you want to integrate in into AcitveScaffold, you’re in for a tough ride.

ActiveScaffold supports has_many :through associations, but not in a way that is compatible with acts_as_taggable_on_steroids. Let me show you.

In your ArticlesController you specify which columns to show. “tag_list” is a stringified version of the tags associated with the Article, which is great for showing to a user.

However, if you want to edit it an article (or create one), I don’t want a text field where I have to enter tags manually, all I want are a bunch of check boxes, so I can check which tags apply to this article.

Showing the check boxes is easy with AS. By default I show ‘tags’, only in the list view do I use ‘tag_list’ instead. Also, make sure to set the ui_type for the tags column to :select. This will show you check boxes, instead of a sub form that allows you to create tags manually.

active_scaffold :article do |config|
    config.columns = [:title, :body, :tags, :author, :created_at]
    config.list.columns = [:title, :author, :tag_list, :created_at]
    config.columns[:tags].ui_type = :select
end

Well, very nice, right. You can now happily select the tags you want, and save your article. Not.

As you may have noticed, the tags are not saved. Why? Acts_as_taggable adds a ‘tags’ attribute to the model, however, when the Article model is saved, the tags attribute is overwritten by the tags specified in the “tags_list” attribute.

The only way to solve this is to convert the tags selected in AS and store them as the tags_list attribute for the Article.

First, let’s add a private method in the ArticleController class:

private

def new_tag_list(tag_ids)
    tag_ids.map {|k,h| h['id']}.collect {|i| Tag.find(i)}.map do |tag|
      tag.name.include?(Tag.delimiter) ? "\"#{tag.name}\"" : tag.name
    end.join(Tag.delimiter.ends_with?(" ") ? Tag.delimiter : "#{Tag.delimiter} ")
end

And add two protected methods that extend the functionality of ActiveScaffold:

protected

def before_create_save(record)
  record.tag_list = new_tag_list(params[:record][:tags])
end

def before_update_save(record)
  record.tag_list = new_tag_list(params[:record][:tags])
end

This will take the actual form values from AS and create a tags_list. This new tags_list is then assigned to the article (named ‘record’ here). The two protected methods process the tags every time an Article is created or updated.

With this in place, you can happily assign tags to your articles! Please let me know if it worked for you, or if you have made any improvements to this solution.