Scope problem with form_remote_tag, ajax?

Hi all,

I have tracked an odd behavior down to what I think is an issue of
scope. In short, when I use form_remote_tag to establish an AJAX form,
my database fields don’t get populated when performing an edit on the
record. Those same fields will get populated using start_form_tag and
no AJAX. I think that Ruby can’t find the local object that represents
the database record…here’s why:

Up front info: table is Issues, one of the text fields in question is
file_number. My use of ajax is to put a subset of the table’s fields on
different tabs in a notebook style. In this example, when the user
clicks on the appropriate link, the fields I’ve considered descriptive
are displayed, and file_number is one of those.

A1. Entering issues_controller.rb
A2. call to issues_controller::edit()

  • B1. within edit, @issue is assigned to issue.find(params[:id])
  • B2. implicit call to render edit.rhtml
    – C1. Rendering edit.rhtml
    – C2. form setup with call to form_remote_tag
    — D1. call to render(:partial => ‘form’)
    ---- E1. Rendering _form.rhtml
    ---- E2. ajax call using link_to_remote( :action =>
    :tab_description_fields )
    ---- (target of ajax call is to a div within the _form.rhtml file)
    ------ F1. Entering issue_controller::tab_description_fields()
    ------ F2. call to render(:layout => false)
    ------ F3. implicit transfer to render of tab_description_fields.rhtml
    ------- G1. Entering tab_description_fields.rhtml
    ------- G2. call of text_field(‘issue’, ‘file_number’)

Hopefully you can follow my whacky scope stack. I’ve been able to
verify that the local var ‘@issue’ that is declared in B1 is available
at E1 (i.e. if I stick the call to text_field(‘issue’,‘file_number’) in
on either side of E2, it gets populated just fine). Once I get into the
tab_description_fields() function and its call to
tab_description_fields.rhtml, the ‘@issue’ var doesn’t seem to be in
scope anymore, so none of the field helpers end up making the link back
to the issue model.

Is there something obvious that I’m missing? Any help or suggestions is
greatly appreciated.

Thanks,

  • David

AHA! I figured it out. If anyone else is interested, here’s what I
learned…

It is indeed a fact that my instance variable ‘@issue’ disappeared from
scope once the template called another function via ajax. A controller
function foo() can set an instance var like @myfoovalue, and the
associated template, foo.rhtml, will have access to that var via “<%=
@myfoovalue %>” but if that template calls other code, the var is not
carried along.

So, the trick is to use the session object to carry this state around.
Using my earlier example, here’s how I did it:

Within issue_controller.rb:

def edit
@issue = Issue.find(params[:id])
# save the issue id into the session object
session[:curr_issue] = @issue
# default behavior is to render edit.rhtml now
end

edit.rhtml sets up the form, and it calls partial render on _form.rhtml
which looks like this:

<%= link_to_remote(‘Description’,
:update => ‘tabbed_area’,
:url => { :controller => ‘issues’,
:action => :tab_description_fields } ) %>

<%= link_to_remote(‘Property Details’,
:update => ‘tabbed_area’,
:url => { :controller => ‘issues’,
:action => :tab_property_fields } ) %>

<%= link_to_remote(‘Financials’,
:update => ‘tabbed_area’,
:url => { :controller => ‘issues’,
:action => :tab_financial_fields } ) %>

<%= link_to_remote(‘Messages’,
:update => ‘tabbed_area’,
:url => { :controller => ‘issues’,
:action => :tab_message_fields } ) %>



Now, back in issue_controller.rb, the functions that correlate to tabs
on the notebook look like:

these functions call their associated *.rhtml files without

rendering the standard templates,

e.g. tab_financial_fields will trigger tag_financial_fields.rhtml

def tab_financial_fields
@issue = session[:curr_issue]
render(:layout => false )
end

def tab_description_fields
@issue = session[:curr_issue]
render(:layout => false )
end

def tab_property_fields
@issue = session[:curr_issue]
render(:layout => false )
end

def tab_message_fields
@issue = session[:curr_issue]
render(:layout => false )
end

Now, the templates that are associated with the tab_* functions get a
valid @issue instance variable and all their text_area calls work just
dandy.

  • David