Noob: UI for many-to-many with has_many :through

Hey All,

I’ve got People and Projects, both of which has_many :through =>
PeopleProjects. PeopleProjects has just one attribute of its own right
now: role (which takes values like ‘programmer’, ‘project manager’
etc.). I believe the models are doing what I need them to–I can add
people to projects (and vice-versa) at the console.

But now I need to add that capability to my views. I’m imagining
something like 2 list boxes, one listing everyone not (yet) assigned to
the project, and the other listing people who are assigned to it. On
this imaginary page I can drag people from one box to the other, and for
those who are assigned to it, easily designate their role with a
drop-down. Of course I’ll settle for check boxes & submit buttons for
managing each list if need be.

I’m assuming there’s no do_what_roy_wants helper for this, so can
anybody point me at tutorials or helpers that do exist that should
help me set something like this up? Or if it’s just not possible w/out
mind-bending Nth-level rails mage skillz, then let me know that.

Thanks!

-Roy

Roy P.
Research Analyst/Programmer
Group Health Center For Health Studies (Cancer Research Network)
(206) 287-2078
Google Talk: rpardee

Roy -

I had to solve a similar problem this morning with users and mailing
list subscription, where the subscription may have additional parameters
that need to be tracked.

If you take this from the perspective of your People -> Edit view, then
you should be able to include something like this to display a series of
checkboxes showing each project - having it checked if this user belongs
to that project:

 <% for proj in Project.find(:all, :order => :name) %>
    <%= check_box_tag "people[project_ids][]", proj.id, 

@people.projects.include?(proj), {:id => “people_project_#{proj.id}”} %>
<%= proj.name %>
<% end %>

Then in your people_controller.rb, for the ‘update’ action:
def update
@people = People.find(params[:id])
@people.project_ids = params[:people][:project_ids]
@people.update_attributes(params[:people])
if @people.valid?
flash[:notice] = “Updated”
redirect_to :action => ‘index’ and return
else
render_action ‘edit’
end
end

The key is that in your People model (people.rb), you need to set the
attr for storing ‘project_ids’, and create an after save method for
ensuring that the relationships are updated properly:

attr_accessor   :project_ids
after_save      :update_projects

# After_save callback to handle mailinglist_ids
def update_projects
    unless projects_ids.nil?
        self.people_projects.each do |p|
            # delete the existing records if they're not in the 

array of ids to keep
p.destroy unless
projects_ids.include?(p.project_id.to_i)
project_ids.delete(p.project_id.to_i)
end
# now build up the new associations
project_ids.each do |p|
self.people_project.create(:project_id => p) unless
p.blank?
end
reload
end
end

Hope that helps,

Richard Luck
DiMax, Inc.
Google Talk: dimaxinc

Very helpful–many thanks!