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

Hi,

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:

user.rb:
has_many :user_tags, :dependent => :destroy
has_many :tags, :through => :user_tags

tag.rb:
has_many :user_tags, :dependent => :destroy
has_many :users, :through => :user_tags

user_tag.rb:
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”)
    user.tags.delete(Tag.find(params[:id]))

  • 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?

Thanks,


Adriano

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]
end

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):

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

destroy:
tag = Tag.find(params[:id])
@user.tags.delete(tag)

I think that this is a satisfactory solution.


Adriano