Problem calling an .rjs template using redirect_to

I've written an .rjs template to update more than one page element at
once. It seems to work perfectly when I call it using a link on the
page, i.e.:

  link_to_remote( image_tag("button_add.gif"), :url =>{:action =>
'side_comment_return', :id => i, :article_id => @article.id } )

But when I attempt to call that same .rjs template from an action that
responds to a form post, i.e.:

  def create_side_comment
    Article.find(params[:id]).comments.create(params[:comment])
    flash[:notice] = "Added comment."
    redirect_to (:action => 'side_comment_return', :id =>
params[:paragraph_id], :article_id => params[:id] )
  end

it spews all of the javascript onto the area of the page that i am
trying to update, rather than simply rendering the html like I expect,
like:

try { Element.update("side_comment3", "\ntest -test

\n"); Element.update("add_comment_button3", "\"Add"); } catch (e) {
alert('RJS error:\n\n' + e.toString());
alert('Element.update(\"side_comment3\", \"\ntest -test

\n\");\nElement.update(\"add_comment_button3\", \"\\"Add\");'); throw e
}

Am I using the redirect_to method inappropriately? Thanks for any help,
this is the first time I've posted a question here, and I appreciate
your time.

Hi Dave, (?)

Basically, you're mixing apples and oranges. Short answer is, you need to use the RJS version of redirect_to.

def create_side_comment
   Article.find(params[:id]).comments.create(params[:comment])
   flash[:notice] = "Added comment."
   render :update do |page|
      page.redirect_to (same_args)
   end
end

hth,
Bill

Thanks for your help, Bill. It seems this hasn't solved my problem,
though... when I try what you have written, rather than updating the
appropriate elements on the page, the browser window redirects to a new
page, the content being the javascript generated by the .rjs template.
Is page.redirect_to not the method I'm looking for?

Thanks again,
Dave

Hi Dave,

yowzadave wrote:

Thanks for your help, Bill. It seems this
hasn't solved my problem, though...

Then no thanks are expected :wink:

when I try what you have written, rather
than updating the appropriate elements on
the page, the browser window redirects to
a new page, the content being the javascript
generated by the .rjs template.

The core of your current difficulty may be rooted (my first ones were) in not fully groking that a Rails app is truly an application: one that lives, except for help from session data, for exactly one request-response cycle. Rails looks at what's requested and does its best to return that. The POST request that invoked the method named create_side_comment told Rails to return html. The RJS template will generate javascript that gets pushed to the browser - by Rails, which has been told to return whatever it returns as html.

Is page.redirect_to not the method I'm looking for?

It would probably help to see the rjs template you've been talking about. Along with an explanation of what it is you're trying to do in this new case. The first, as stated, is a correct use of RJS templates.

Best regards,
Bill

Ok, here's the idea:

There are a number of paragraphs in an "article," and the user has the
option to click a link next to each paragraph, to add a comment to that
paragraph. That link calls the .rjs action/template i've called
"side_comment," with the controller looking like this:

  def side_comment
    @paragraph_id = params[:id]
    @article_id = params[:article_id]
  end

and the .rjs template looking like this:

page.replace_html "side_comment#{@paragraph_id}", :partial =>
'side_comment_form'

page.replace_html( "add_comment_button#{@paragraph_id}",
                  link_to_remote ( image_tag('button_minus.gif',
                          :alt => 'Return to comments view',
                          :title => 'Return to comments view'),
                          :url => {:action => 'side_comment_return',
                            :id => @paragraph_id,
                            :article_id => @article_id }) )

So when the user clicks the button, it updates a div next to that
paragraph with a form asking for the various elements of the comment,
and also changes the button to a different state (from a plus to a
minus). If the user clicks this button again, it calls the .rjs
action/template "side_comment_return," which switches the element
containing the form back to its original state, and also changes the
button back to its original state. This seems to be working correctly.

The problem is, when the user completes and submits the form, I would
like both the element with the form and "add_comment_button" to switch
back to the initial view. So I thought I'd use the same action,
"side_comment_return", that I am using in the previously described
case. The .rjs for that action looks like this:

page.replace_html( "side_comment#{@paragraph_id}", :partial =>
'list_side_comments' )

page.replace_html( "add_comment_button#{@paragraph_id}",
                  link_to_remote( image_tag('button_add.gif',
                  :alt => 'Add comment to this paragraph',
                  :title => 'Add comment to this paragraph'),
                  :url => {:action => 'side_comment',
                    :id => @paragraph_id,
                    :article_id => @article_id } ) )

So my thinking was, the method "create_side_comment" that my comment
form invoked could just redirect to the "side_comment_return" method
when it was finished...but I haven't yet been able to get this working,
as described earlier. Anyhow, I hope this clarifies what I'm trying to
do.

Cheers,
Dave

Hi Dave,

Sorry for my delay in replying.

yowzadave wrote:
<snip>

So when the user clicks the button, it updates
a div next to that paragraph with a form [...]

<snip>

The problem is, when the user completes and
submits the form [...]

And sorry I didn't pick up on this sooner. Given the symptom you're describing (i.e., getting html displayed when you want js executed) I'd guess the problem's coming from your form. That is, your form submission is telling the server it's expecting a response that's html to display, not js to execute. If you're not already using it, switch to form_remote_tag and let us know if the problem persists.

hth,
Bill

Bill:

I'm already using form_remote_tag; the whole _side_comment_form partial
I'm using looks like this:

<%= form_remote_tag(:update => "side_comment#{@paragraph_id}",
                    :url => { :action => "create_side_comment", :id =>
@article_id, :paragraph_id => @paragraph_id } ) %>
  <label for="comment_author">Name:</label><br />
  <%= text_field 'comment', 'author' %><br />
<label for="comment_body">Comment:</label><br />
  <%= text_area 'comment', 'body', :cols => "40", :rows => "5" %>
  <%= submit_tag "Post Comment" %>
<%= end_form_tag %>

In fact, I've already been able to get the form to update correctly in
place on the page by simply bypassing the .rjs template and putting

redirect_to (:action => 'list_side_comments', :paragraph_id =>
params[:paragraph_id], :article_id => params[:id] )

at the end of the create_side_comment def in the controller.
Unfortunately, this doesn't allow me to update the other element on the
page at the same time, as I'd hoped to do by using .rjs...

Thanks again,
Dave

yowzadave wrote:

Bill:

I'm already using form_remote_tag; the whole _side_comment_form partial
I'm using looks like this:

<%= form_remote_tag(:update => "side_comment#{@paragraph_id}",
                    :url => { :action => "create_side_comment", :id =>
@article_id, :paragraph_id => @paragraph_id } ) %>
  <label for="comment_author">Name:</label><br />
  <%= text_field 'comment', 'author' %><br />
<label for="comment_body">Comment:</label><br />
  <%= text_area 'comment', 'body', :cols => "40", :rows => "5" %>
  <%= submit_tag "Post Comment" %>
<%= end_form_tag %>

In fact, I've already been able to get the form to update correctly in
place on the page by simply bypassing the .rjs template and putting

redirect_to (:action => 'list_side_comments', :paragraph_id =>
params[:paragraph_id], :article_id => params[:id] )

at the end of the create_side_comment def in the controller.
Unfortunately, this doesn't allow me to update the other element on the
page at the same time, as I'd hoped to do by using .rjs...

Thanks again,
Dave

>

Hey Bill

Try removing the :update option from your form_remote_tag. If you're
using RJS this isn't necessary and in my experience spews the returned
RJS code into the specified element. The example link_to_remote you gave
for example omitted the :update parameter and thus acted as was to be
expected.

try:

<%= form_remote_tag(:url => { :action => "create_side_comment",
                    :id => @article_id,
                    :paragraph_id => @paragraph_id } ) %>

#controller

def create_side_comment
  @article_id = params[:id]
  @paragraph_id = params[:paragraph_id]

  Article.find(@article_id).comments.create(params[:comment])

  flash[:notice] = "added comment"
  render(:action => "side_comment_return")
end

I rarely use rjs templates, preferring to do the one or two lines I make
use of in-line with render(:update).

In case something doesn't work, the idea here is that the normal action
takes place, then it renders the 'side_comment_return' action's rjs
template (as all that needs is @article_id and @paragraph_id: both
present in the current action). No redirect is necessary.

Cheery-o
Gustav Paul

Gustav Paul

Try removing the :update option from
your form_remote_tag.

Paul is exactly right. The :update option should not be used if you're trying to update multiple DOM elements. That's what rjs is for. Very common misunderstanding.

If you're using RJS this isn't necessary and in
my experience spews the returned RJS code
into the specified element. The example
link_to_remote you gave for example omitted
the :update parameter and thus acted as was to
be expected.

Best regards,
Bill

> Try removing the :update option from
> your form_remote_tag.

This worked perfectly. Thanks for your help, guys, and sorry I wasn't
able to point you to the offending code earlier. I appreciate your time
a lot,

Dave Anderson