简体   繁体   中英

Rendering partial with AJAX link_to in Rails

After completing Hartl's tutorial I'm trying to implement @replies for the Micropost model.

I wanted the reply button on a micropost to render the micropost form right there under said post a la twitter. I also wanted to pass the :micropost_id of said post to the reply so that I could later reference which post it was a reply to, again a la twitter.

I've been trying to implement some of that based on the answer to this question .

My microposts controller has

def reply_form

    respond_to do |format|
      format.js
    end
  end

The link in the view is

<%= link_to 'reply', 'shared/reply_form', remote: true, locals: { object: :id } %>

With my attempt there to pass on the micropost :id

After a post I have this for the partial to be rendered in:

<div id="ReplyContainer"></div>

I then have _reply_form.js.erb

$('#ReplyContainer').html('<%=j render partial: 'shared/reply_form', locals: { object: :id } %>')

It's not throwing errors but clicking the 'reply' link has no effect and does not render the _reply_form.html.erb partial.

My ultimate goal is you click reply, that renders the micropost form, with @username at the start of the message (derived from the micropost_id?) submitting that form then saves the new micropost including the micro post_id of the original post in the reply_to column that I've created in my microposts table. Any nudges in the right direction much appreciated. Don't want to be barking up the completely wrong tree. Thanks.

EDIT: I'm currently getting a routing error when clicking the reply link.

(No route matches [GET] "/shared/reply_form")

But as far as I can see everything is in the right place.

Ok, sorry, I've just read better your question and the problem is related to the wrong structure.

  • you have a controller with an action that will render the post
  • your post page will be composed by the "post" and many replies
  • each reply I guess is made of a partial (let's say a _reply.html.erb file).

The structure of the page will be then the following:

<div>
 ... my post here...
</div>
<div id='repliesContainer'>
<%- @replies..each do |id| -%>
    <%= render :partial => "shared/reply", :locals => { :object => id} %>
<%- end -%>
</div>

And we call it post.html.erb .

This is will be your shared/_reply.html.erb file:

  // note here that the id of the div contains the ID of the reply: each ID must be unique in the page....
  <div id='ReplyContainer-#{object}'>
    ...reply content here...
  </div>

Now, your post.js.erb file contains the following:

$('#repliesContainer').append("<%= escape_javascript( render :partial => 'shared/reply', :locals => { :object => id}) -%>");

The content of the append() function will be rendered on the server as a string from the partial.

You have several problems here:

  1. As you discovered, the route to your reply form is incorrect. Until you get this fixed, you won't be able to debug the rest of the system. Run rake routes | grep reply_form rake routes | grep reply_form to find the URL for it (it won't be under /shared most likely), then see what the response is for that URL. I bet it throws an error (see #2).

  2. Your reply form file has the wrong name: _reply_form.js.erb is a partial but it needs to be 'reply_form.js.erb'. If you hit the correct route for that controller, you'll get a 'Missing Template' error because it is looking for a normal template, not a partial.

  3. Finally, the reply_form.js.erb code needs to point to the shared reply_form partial, so if is really in shared/_reply_form.html.erb then the JS response should be rendered correctly.

Having said that...I really dislike sending Javascript back to the browser, in part because it makes debugging JS much harder - how are you going to find the returned code in your browser debugger? There may be some use cases for this type of design but they are probably very rare.

The better / more idomatic solution is to send JSON data (eg. the rendered text) back to the browser and have some handler parse the JSON and update the DOM. This way all of your JS code is present in the browser and all you are receiving is data. This will be much easier to debug.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM