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.



Roy Pardee 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]",, @people.projects.include?(proj), {:id => "people_project_#{}"} %>         <%= %>      <% 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!