Design - Best practices on managing many-to-many controllers?


This may seem a silly question, but I didn’t find an elegant solution
to manage a user’s tag collection. Perhaps I’m missing something, I’d
like to know if there is a better way to handle it are.

The configuration is pretty standard stuff:

has_many :user_tags, :dependent => :destroy
has_many :tags, :through => :user_tags

has_many :user_tags, :dependent => :destroy
has_many :users, :through => :user_tags

belongs_to :user
belongs_to :tag

(tags also have many-to-many associations w/ other resources).

I would like users to have a separate page to manage their tags.

I have thought about some solutions:

  • Manage the tags using different templates for user actions. Problem:
    doesn’t scale, will add complex logic to controllers.

  • Extend the users resource with two new member actions. Problem:
    doesn’t scale, users will have many more collections.

  • Create a controller for user_tags, nest the resource under users.
    This is what I’m using now. It doesn’t feel right to manipulate the
    user_tags table directly, Rails already has logic for things like:

    user.tags << Tag.find_or_create_by_name(“foo”)

  • Create a non-restful controller, maybe to manage all users’
    collections, keeping things in one place. Add routes manually. In
    particular, leverage the construct:

    accepts_nested_attributes_for :tags, …

Any thoughts?



I decided to create a restful controller for the tags, nested in the
users resources, and not associated with any model:

resources :users do
resources :utags, :only => [:index, :create, :destroy]

I’m using these routes in the views:

<%= link_to ‘destroy’, user_utag_path(@user, tag), :method
=> :delete %>

<%= form_tag user_utags_path(@user) do %>

And in the controller (no error handling for now):

tag = Tag.find_or_create_by_name(params[:name])
@user.tags << tag

tag = Tag.find(params[:id])

I think that this is a satisfactory solution.