HABTM / Dropdown Help Needed

I’m terribly new to Rails, so bear with me.

I have an application I am working on which deals with projects and
subcontractors. There can be several subs on each project and each sub
can work on several projects. I have my join table set up and
has_and_belongs_to_many in both models. If I manually put data in the
join table, this works in my show view:

<% for subcontractor in @project.subcontractors %>
<%= subcontractor.name %>

<% end %>

I get the correct list of subcontractors belonging to this project.

My question is this: How do I get data into the join table? If I were
doing this in PHP, I would have a button that said “Add a Subcontractor”
that would pop up a window with a dropdown where the user would select a
sub. I would then refresh the page and then refresh the page and the new
sub would appear in the list.

What is the “Rails Way” to do the same thing? I want the user to select
a sub from a dropdown, but I have no idea how to implement this. Let me
phrase that better, I know how to use collection_select for a “normal”
lookup table situation where I have has_many and belongs_to. It’s this
habtm situation that has me stymied. What needs to go in the controller
and what needs to go in the view for this to work?

Any help is sincerely appreciated.

Bob Boyken wrote:

I get the correct list of subcontractors belonging to this project.
lookup table situation where I have has_many and belongs_to. It’s this
habtm situation that has me stymied. What needs to go in the controller
and what needs to go in the view for this to work?

You can do the same thing you’d do in PHP in Rails.

The popup would be called from the main edit_project page with:

<%= link_to ‘Add a subcontractor’,
{:action => ‘add_subcontractor’, :id => @project.id} %>,
:popup => [‘new_window’, ‘height=300, width=600’] %>

The RHTML for the pop-up would be:

<%= form_tag %>
<%= select_tag ‘subcontractor_id’,
options_for_select([[‘Select a subcontractor to add’,0]] +
Subcontractor.find(:all).map {|s|
[s.name,s.id]}),
:onchange => ‘this.form.submit(); window.close()’ %>
<%= end_form_tag %>

The controller code for the pop-up would be:

def add_subcontractor
if request.post?
project = Project.find(params[:id])
sid = params[:subcontractor_id].to_i
project.subcontractors << Subcontractor.find(sid) if sid != 0
render :nothing => true
end
end

You could even get away without the need to refresh the edit_project
window by adding to the select on_change

  window.opener.add_subcontractor(value)

and having this function insert the subcontractor into the HTML list
from a JavaScript subcontractor id-to-name array or hash.

However there would be no check that there was no error while
adding the subcontractor in the controller unless you delayed
this callback to the parent window until after the post returned
successfully.


We develop, watch us RoR, in numbers too big to ignore.