Serializing a non-form input for a link_to_remote call--how to do it?

Hey All,

I’m still working on my ‘add people to this project’ feature for my /
projects/edit view. I’ve got a very nice AJAX search feature (thanks
to the kind help here) that allows users to generate a list of people
to potentially add to the project they’re editing. I’ve also got an
AJAX ‘add this found person to this project’ feature MOSTLY working–
am writing for help on fixing the last issue w/that.

Model wise, I’ve got Project & Person in a many-to-many, and
ProjectPerson as the join model (so, Project
has_many :people, :through => :project_person). The join model
ProjectPerson has just one attribute of its own–role. My problem is
that I can’t figure out how to allow the user to edit this field
before adding the association between the Project and the Person.

Here’s the code I’m using to do the add. The AJAX search feature
renders a partial that spits one of these out for each person meeting
the search:

<%= h p.person.nom %> <%= h p.person.organization.abbreviation %> <%= select(p, :role, Person::ROLE_NAMES, :selected => p.person.typical_role) %> <%= link_to_remote('Add', :url => {:controller => "project_people", :action => "create", :person_id => p.person, :project_id => p.project, :role => p.role #<-- Problem is here. }, :update => 'roster', :method => 'post' ) %>

(‘p’ here is an instance of ProjectPerson). The select() helper gives
me a nice drop-down, and p.person and p.project are both getting
properly transmitted to the project_people.create action, but p.role
is always blank. I suspect this is b/c at the time this is transmuted
into HTML/javascript, p.role is blank, and there’s nothing in my
link_to_remote() call to tell the browser to go get whatever the user
put in the drop-down corresponding to the call to select(). If that’s
it, I don’t know how to do that (and when I go to ‘view source’ on the
page the AJAXy bits don’t show up, so I don’t know how to investigate
that). Assuming anybody’s read this far, can you advise? (Do I need
to use remote_form_for maybe?)

Inicdentally, if I change the indicated argument to:

:role => p.person.typical_role

Then I do indeed get the contents of person.typical_role written to
project_person.role. But I really want to allow the user to override
that.

A thousand thanks in advance!

-Roy

Roy,

the way you have it set up now, the “role” in the url of the
link_to_remote is getting generated on the server side and isn’t
linked to the select list.

Your instincts are right: you should be using remote_form_for here.

Ah, okay then–more reading/experimenting for me… :wink:

Thanks!

-Roy

Drat–remote_form_for is not working as desired. I’ve replaced my
partial with this here:

<% remote_form_for(:project_person, p, :url => {:controller =>
“project_people”, :action => “create”}) do |pp_form| %>

<%= h p.person.nom %>
<%= h p.person.organization.abbreviation %>
<%= pp_form.select(:role, Person::ROLE_NAMES, :selected =>
p.person.typical_role) %>
<%= submit_tag ‘Add’ %>
<% end %>

But when I click the submit button for this, the browser posts the
outer form–the one for editing the project. I tried making that
submit_tag call pp_form.submit_tag, but that just got me a (undefined
method `submit_tag’ for #<ActionView::Helpers::FormBuilder:
0x4987c3c>).

Can you not nest a remote form inside a regular form_for block?

Thanks!

-Roy

On 30 Apr 2008, at 19:21, Roy P. wrote:

But when I click the submit button for this, the browser posts the
outer form–the one for editing the project. I tried making that
submit_tag call pp_form.submit_tag, but that just got me a (undefined
method `submit_tag’ for #<ActionView::Helpers::FormBuilder:
0x4987c3c>).

Can you not nest a remote form inside a regular form_for block?

Nesting forms is not legal html.

Fred

On 29 Apr 2008, at 22:49, Roy P. wrote:

                            :project_id  => p.project,
                            :role        => p.role     #<--

<%= link_to_remote(‘Add’,
:url => {:controller => “project_people”,
:action => “create”,
:person_id => p.person,
:project_id => p.project},
:with => “‘role=’+encodeURIComponent($F(‘project_role’))”

(change project_role to the id of your select tag)

Fred

On 30 Apr 2008, at 20:28, Roy P. wrote:

Thanks Fred! The problem is that I don’t know how to control what
that id winds up being. I tried throwing an :id argument on my call
to select, like so:

select(p, :role, Person::ROLE_NAMES, :selected =>
p.person.typical_role, :id=>“p_role[]”)

select(p, :role, Person::ROLE_NAMES, {:selected =>
p.person.typical_role}, :id=>“foo”)

(Figured I’d need the empty brackets b/c there are going to be a
series of these–one per found person). But even still I get IDs like
“__ProjectPerson:0x4a43734_role”.
dom ids aren’t allowed to contain[]

BTW–do I take it that, not only is nesting elements verboten
HTML, but having a series of separate form elements is also no good?
I tried taking my remote_form_for stuff entirely outside the main
form, but it seemed to have no effect…

Not sure what you mean by that.

On Apr 30, 11:39 am, Frederick C. [email protected]
wrote:

                   :url => {:controller  => "project_people",
                    :with => "'role='+encodeURIComponent($F('project_role'))"

(change project_role to the id of your select tag)

Thanks Fred! The problem is that I don’t know how to control what
that id winds up being. I tried throwing an :id argument on my call
to select, like so:

select(p, :role, Person::ROLE_NAMES, :selected =>
p.person.typical_role, :id=>“p_role[]”)

(Figured I’d need the empty brackets b/c there are going to be a
series of these–one per found person). But even still I get IDs like
“__ProjectPerson:0x4a43734_role”.

BTW–do I take it that, not only is nesting elements verboten
HTML, but having a series of separate form elements is also no good?
I tried taking my remote_form_for stuff entirely outside the main
form, but it seemed to have no effect…

Thanks!

-Roy

select(p, :role, Person::ROLE_NAMES, {:selected =>
p.person.typical_role}, :id=>“foo”)
(Figured I’d need the empty brackets b/c there are going to be a
series of these–one per found person). But even still I get IDs like
“__ProjectPerson:0x4a43734_role”.

dom ids aren’t allowed to contain[]

Taking those out does not seem to affect the id of the select input–
it’s still unpredictable objectid goo. Can you tell me how to control
what those IDs are set as? Or advise on how I can otherwise get a
handle on the value of the select input so I can stuff it in the :with
argument of link_to?

BTW–do I take it that, not only is nesting elements verboten
HTML, but having a series of separate form elements is also no good?
I tried taking my remote_form_for stuff entirely outside the main
form, but it seemed to have no effect…

Not sure what you mean by that.

Earlier in the thread I asked if it was verboten to have a
remote_form_for nested w/in a form_for. You replied saying (I
thought) that it was illegal to have nested elements per the
HTML standard. So I’m asking if it’s also illegal to have multiple

elements in general? Would also be illegal? If not, conceivably I could move my remote_form_for block outside the form_for block and have a hope of it working. (My experiment with doing that did not work.)

Thanks!

-Roy

On 30 Apr 2008, at 21:00, Roy P. wrote:

Taking those out does not seem to affect the id of the select input–
it’s still unpredictable objectid goo. Can you tell me how to control
what those IDs are set as? Or advise on how I can otherwise get a
handle on the value of the select input so I can stuff it in the :with
argument of link_to?

I rather mangled my previous mail: to set the id of the select tag,
you need

select(p, :role, Person::ROLE_NAMES, {:selected =>
p.person.typical_role}, :id=>“foo”)
(note the extra {})

thought) that it was illegal to have nested elements per the
HTML standard. So I’m asking if it’s also illegal to have multiple

elements in general? Would also be illegal? If not, conceivably I could move my remote_form_for block outside the form_for block and have a hope of it working. (My experiment with doing that did not work.)

You can have as many forms as you want.

Fred

I rather mangled my previous mail: to set the id of the select tag,
you need

select(p, :role, Person::ROLE_NAMES, {:selected =>
p.person.typical_role}, :id=>“foo”) (note the extra {})

Kick-ass–thanks! I’m finding it tough to know which args should get
batched up together into explicit hashes. I suppose that’s a part of
the learning curve here…

Now since this call is part of a loop through a collection, I had to add
a counter var to unique-ify the ids:

<% row_num = 0 %>
<% for p in ppl %>
<% row_num += 1 %>
<% role_id = “p_role_#{row_num.to_s}” %>

">
<%= h p.person.nom %>
<%= h p.person.organization.abbreviation
%>
<%= select(p, :role, Person::ROLE_NAMES,
{:selected => p.person.typical_role}, :id => role_id) %>
<%= link_to_remote(‘Add’,
:url => {:controller => “project_people”,
:action => “create”,
:person_id => p.person,
:project_id => p.project,
:role => p.role},
:update => ‘roster’,
:method => ‘post’,
:with =>
“‘role=’+encodeURIComponent($F(’#{role_id}’))”
) %>
  </tr>

I’m fine w/that, tho it does feel a bit ghetto to me. Is there a better
way?

Thanks so much for taking the time!

-Roy

On 1 May 2008, at 02:44, Pardee, Roy wrote:

the learning curve here…
Basically you can only omit the hash braces when it’s the last
argument (how would ruby know where to draw the line).

"> :role => p.role}, better way?

Well I’d probably use each_with_index rather than the for loop, but
that’s largely a question of taste. It probably looks neater when it’s
not line wrapped to fit in an email.

Fred

Hi Roy,

Roy P. wrote:

Can you not nest a remote form inside a regular form_for block?

No, you cannot nest forms. That’s what the W3C spec says. You can put
multiple forms on a page. And you can make them appear, visually, to
be
nested. But you can’t have a form tag within a form tag.

HTH,
Bill

@Roy,

It appears that you’re using the row_num (or index of each_with_index)
to artificially create a unique dom id so that you can submit that dom
id with the link_to_remote. Is that accurate? If so, I’d suggest
that you use the person.id rather than creating an artificial one.
Specifically, your ‘role_id’ could be “p_role_#{p.id}”. Assuming that
your ppl collection returns each person only once then you’ve got
unique dom_ids every time.

Even better, if you’re in Rails 2.x, you can use the dom_id helper
method to create the id for you. You’d call it like this:

dom_id(p, :select_role_for) => ‘select_role_for_person_12’

The first parameter is a model object. The helper uses the class name
and id to form the base name in the dom id (here, person_12). The
optional symbol after that is used as a prefix, giving you a nice,
expressive id for your select element. Put those together and you
could have something like this:

<% ppl.each do |employee| %>

<%= h employee.person.nom %> <%= h employee.person.organization.abbreviation %> <%= select(employee, :role, Person::ROLE_NAMES, {:selected=>employee.person.typical_role}, :id=>dom_id(employee, :role_for) %> <%= link_to_remote 'Add', :url=>project_people_path(employee.project, :person_id=>employee.person), :method=>:post, :update=>'roster', :with => "'role=' + encodeURIComponent($F('#{dom_id(employee, :role_for)}'))" ) %> <% end %>

HTH,
AndyV