div_for

70 views
Skip to first unread message

fugee ohu

unread,
Jun 16, 2017, 4:14:00 PM6/16/17
to Ruby on Rails: Talk
The anchor doesn't get rendered I didn't know what to use for the element name so I used the same as I used the same variable I passed to div_for in my view, commentable Thanks in advance


View:
 <%= div_for(commentable) do %> 
 <% end %>

js.erb
$(document).on('turbolinks:load', function(){ 
  $('#commentable').each(function(){ 
    var elm = $(this); 
    elm.append('<a href="/comments/new?commentable_id=' + elm.attr('id').split('_')[1] + '">Comment</a>'); 
 }); 
}); 


Walter Lee Davis

unread,
Jun 16, 2017, 6:47:49 PM6/16/17
to rubyonra...@googlegroups.com
There can only be one instance of an ID on any given page. And nothing you did in this example will render the id #commentable. If you look at my example, I did not use an ID on each element. The selector in $('#commentable').each should be $('#parent_of_the_list div'), and you'll have to apply whatever ID you want to search for to a parent element of the commentables. If you want to do this in a slightly simpler manner, you could apply a classname to the commentables, using the div_for helper: <%= div_for(commentable, class: 'commentable') do %>. Then you can change the jQuery to $('.commentable') and that will also work.

Walter

fugee ohu

unread,
Jun 17, 2017, 3:53:06 AM6/17/17
to Ruby on Rails: Talk
I'm render posts/index from a page called page.html.erb in the world controller and that in turn renders index action in posts controller and _index partial which in turn renders _post.html.erb The javascript anchor tag is in the top level view, page.html.erb The javascript has no effect on the html rendered No comment links displayed Thanks in advance




_post.html.erb
<%= div_for(post, class: 'post') do %> 
    <%= simple_format post.content %> 
    <% unless post.attachment.blank? %>
      <%= image_tag(post.attachment, height: 250) %><br>
    <% end %>
<%- end -%>

$(document).on('turbolinks:load', function(){ 
  $('#posts div').each(function(){ 
    var elm = $(this); 
    elm.append('<a href="/comments/new?post_id=' + elm.attr('id').split('_')[1] + '">Comment</a>'); 
  }); 
});  

fugee ohu

unread,
Jun 18, 2017, 7:58:43 PM6/18/17
to Ruby on Rails: Talk


On Friday, June 16, 2017 at 6:47:49 PM UTC-4, Walter Lee Davis wrote:


Since I'm returning the new comment form shouldn't it be rendered in a div that looks something like post_14_comment_5 or something

fugee ohu

unread,
Jun 18, 2017, 8:05:23 PM6/18/17
to Ruby on Rails: Talk


On Friday, June 16, 2017 at 6:47:49 PM UTC-4, Walter Lee Davis wrote:

This isn't working I think since it's a link in the view i should use $('#post div).click.(function(){ but this isn't rendering anything The log shows the js file was rendered but nothing was added to the page
 
$(document).on('turbolinks:load', function(){
  $('#post div').click.(function(){
    var elm = $(this);
    elm.append('<%= form_for @comment do |f| %>  <%= f.hidden_field :commentable_id, value: @comment.commentable_id %><%= f.hidden_field :commentable_type, value: @comment.commentable_type %>  <div class="field form-group">        <%= f.text_area :body, class: 'form-control' %>      </div>      <div class="field form-group">        <%= submit_tag "Post comment", class: 'btn btn-primary' %>      </div>    <% end %>');
  });
}); 
 

fugee ohu

unread,
Jun 18, 2017, 8:24:03 PM6/18/17
to Ruby on Rails: Talk


On Friday, June 16, 2017 at 6:47:49 PM UTC-4, Walter Lee Davis wrote:

 Here's my page souce and js.erb it's not appening anything to the page with the render

<div class="post">
  <p>Doing nothing as usual</p> 
  <a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=14&amp;comment%5Bcommentable_type%5D=Post">Comment</a>
</div>
<div class="post" id="post_14">
</div>


$(document).on('turbolinks:load', function(){
  $('#post div').click.(function(){ 
var elm = $(this);

Walter Lee Davis

unread,
Jun 18, 2017, 11:28:04 PM6/18/17
to rubyonra...@googlegroups.com
Show me the content_tag_for code you are using in your view. Copy and paste. The id that will be rendered depends on the instance variable that you send into the helper. It doesn't care about the surrounding page or the route that it took to render it.

If you pass in <%= content_tag_for :li, @foo do %> then you will get <li id="foo_124">, no matter on which page you put this. (The controller for that page must set @foo to be an ActiveRecord object, but that's the only expectation.)

Walter

Walter Lee Davis

unread,
Jun 18, 2017, 11:30:27 PM6/18/17
to rubyonra...@googlegroups.com
You've skipped over the last set of instructions I sent you, and you really need to do this in order or it will never make sense. Show me the code you are using that loads the form into another page, and please don't post it unless it is working in a browser and you can save comments. Get that far, and THEN I will be happy to help you take it into Ajax land.

Walter

fugee ohu

unread,
Jun 20, 2017, 3:29:21 AM6/20/17
to Ruby on Rails: Talk

 _post.html.erb

<%= content_tag_for(:div, post) do %>

    <%= simple_format post.content %>
    <% unless post.attachment.blank? %>
      <%= image_tag(post.attachment, height: 250) %><br>
    <% end %>
    <%= link_to 'Comment', new_comment_path( 'comment[commentable_type]': 'Post', 'comment[commentable_id]': post.id), remote: true %>
    <%= content_tag_for(:div, post, :comment) do %>
    <% end %>
<% end %>

produces

<div class="post" id="post_13">
	<p>listening to blues</p> 
	<a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=13&amp;comment%5Bcommentable_type%5D=Post">Comment</a>
	<div class="comment_post" id="comment_post_13">
</div></div><div class="post" id="post_14">

	<p>Doing nothing as usual</p> 
	<a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=14&amp;comment%5Bcommentable_type%5D=Post">Comment</a>

	<div class="comment_post" id="comment_post_14">
</div></div>

new.js.erb
$('#post comment div)click.(function(){

This doesn't produce anything


Walter Lee Davis

unread,
Jun 20, 2017, 8:52:58 AM6/20/17
to rubyonra...@googlegroups.com
You may want to insert the existing comments here:

<%= render post.comments %>

Then you can inject the form at the top or the bottom of the list. Remember, you'll need a _comment.html.erb partial in the views/comments folder for the short-hand to work.

> <% end %>
> <% end %>
>
> produces
>
> <div class="post" id="post_13">
> <p>listening to blues</p>
>
>
> <a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=13&amp;comment%5Bcommentable_type%5D=Post">Comment</a>
> <div class="comment_post" id="comment_post_13">
> </div></div><div class="post" id="post_14">
> <p>Doing nothing as usual</p>
>
>
> <a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=14&amp;comment%5Bcommentable_type%5D=Post">Comment</a>
> <div class="comment_post" id="comment_post_14">
> </div></div>
>
> new.js.erb
> $('#post comment div)click.(function(){
>
> This doesn't produce anything

That's not surprising. Your RJS handler is going to be rendered with the same parameters that new.html.erb is when it creates a new page. So what you do in that instance is not observe a click (that click already happened) but rather identify the parts of the page that you want to replace, and replace them with the parts you need to insert. You're already on the other side of the click.

The content_tag_for method has a partner: dom_id(element, name_addition=nil). It produces just the ID for the element, not the entire element.

Inside the new.js.erb, rather than having the <%= render 'form' %> just spew out some HTML, you target where that should go:

$('#<%= dom_id(post, :comment) %>').prepend('<%=j render( 'comments/form' ) %>');

That will expand to $('#comment_post_14').prepend('<form ... >'); which will inject the form into the top of the comment_post_N container.

Trouble is, it will also do that again and again if you click the link repeatedly. To get around that, you could put the link to add a comment inside the container you want to fill with the form, and then use the jQuery html() method to replace the contents. That would look the same as above, just replace prepend with html. This gets around you needing to test if the form is already there, because the moment you click the link, the link is replaced with the form and you can't click it again.

So you have something like this in the end:

<%= content_tag_for(:div, post) do %>
<%= simple_format post.content %>
<% unless post.attachment.blank? %>
<%= image_tag(post.attachment, height: 250) %><br>
<% end %>
<%= content_tag_for(:div, post, :new_comment) do %>
<%= link_to 'Comment', new_comment_path( 'comment[commentable_type]': 'Post', 'comment[commentable_id]': post.id), remote: true %>
<% end %>
<%= content_tag_for(:div, post, :comments) do %>
<%= render post.comments %>
<% end %>
<% end %>

The new.js.erb becomes this:

$('#<%= dom_id(post, :new_comment) %>').html('<%=j render( 'comments/form' ) %>');

And then to update the page, you want to render just that post again into the list. This is why you wanted to have the posts/index.html.erb depend on a _post.html.erb partial to render the list -- you're automatically set up to do this last step.

Make sure that your form_for method includes the remote: true configuration pair. This will submit the form via Ajax.

In comments_controller.rb, make sure you have a respond_to block for :js in the #create method. In case of an error, it will need to render the :new method again, but if the save succeeds, it should just render the create.js.erb by default (pass an empty block to that content_for).

create.js.erb would be something like this:

$('#<%= dom_id(@comment.post) %>').replaceWith('<%=j render @comment.post %>');

And that's really it. If it doesn't work, it's probably a typo on my part.

Walter


>
>
>
> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/3fea1525-2b10-4718-9fa0-b6d04216aa51%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

fugee ohu

unread,
Jun 20, 2017, 2:57:38 PM6/20/17
to Ruby on Rails: Talk
In _post.html.erb ?

Walter Lee Davis

unread,
Jun 20, 2017, 5:37:52 PM6/20/17
to rubyonra...@googlegroups.com

> On Jun 20, 2017, at 2:57 PM, fugee ohu <fuge...@gmail.com> wrote:
>
> <%= content_tag_for(:div, post) do %>
> <%= simple_format post.content %>
> <% unless post.attachment.blank? %>
> <%= image_tag(post.attachment, height: 250) %><br>
> <% end %>
> <%= content_tag_for(:div, post, :new_comment) do %>
> <%= link_to 'Comment', new_comment_path( 'comment[commentable_type]': 'Post', 'comment[commentable_id]': post.id), remote: true %>
> <% end %>
> <%= content_tag_for(:div, post, :comments) do %>
> <%= render post.comments %>
> <% end %>
> <% end %>


This part would go into _post.html.erb

Walter

fugee ohu

unread,
Jun 21, 2017, 3:25:54 AM6/21/17
to Ruby on Rails: Talk

List comments and inject the form at the top or bottom of the list, what about a link to new comment we skipped over that no?

fugee ohu

unread,
Jun 21, 2017, 3:52:42 AM6/21/17
to Ruby on Rails: Talk

How do I give new.js.erb the right element name
   $('#comment_post)click.(function(){
In this line there's no id number

 

Walter Lee Davis

unread,
Jun 21, 2017, 8:34:17 AM6/21/17
to rubyonra...@googlegroups.com

> On Jun 21, 2017, at 3:52 AM, fugee ohu <fuge...@gmail.com> wrote:
>
> How do I give new.js.erb the right element name
> $('#comment_post)click.(function(){
> In this line there's no id number

I think you may have missed a few bits of my reply. We are not observing a click any more. Everything is out of the jQuery pool, and fully into the RJS pool. If you're viewing this in the Google Groups (Web) view, you may need to expand all of the little ... ellipses in order to see all of my threaded replies.

Walter
Message has been deleted
Message has been deleted

fugee ohu

unread,
Jun 27, 2017, 12:40:33 AM6/27/17
to Ruby on Rails: Talk

in the second content_tag_for statement collection: post.comments fails to produce anthing for comment.body when the _comment.html.erb partial is rendered

_post.erb.html


 <%= content_tag_for(:div, post) do %>
    <%= simple_format post.content %>
    <% unless post.attachment.blank? %>
      <%= image_tag(post.attachment, height: 250) %><br>
    <% end %>
    <%= content_tag_for(:div, post, 'comments') do %>
        <%= render '/comments/comment', collection: post.comments %>
        <%= content_tag_for(:div, post, 'comment_form_holder') do %>
            <%= link_to 'Comment', new_comment_path('comment[commentable_id]': post.id, 'comment[commentable_type]': 'Post') %><br><br>

        <% end %>
    <% end %>
<% end %>


_comment.html.erb

<%= content_tag_for(:div, @comments) do %>
    <%= simple_format comment.body %>
    <%= comment.post.user.first_name comment.post.user.last_name %>
<% end %>

Walter Lee Davis

unread,
Jun 27, 2017, 7:32:33 AM6/27/17
to rubyonra...@googlegroups.com
content_tag_for builds the DIV and gives it an ID based on a single item passed to it. I'm not sure what it would make of a collection of comments, which is what you're passing it here. What I think you need to do is change @comments to comment, to match the rest of the local variables inside the partial. @comments doesn't exist inside the partial unless you render it in a scope that already had that set as an instance variable. comment exists inside the partial because the partial is named comment, but that's only true if you are either rendering it with the "shortcut" collection: @comments, where @comments is an array or association of individual comment instances, or are rendering it one at a time, and passing in locals: { comment: @comment } or similar. Because you are doubly-nested at this point, inside _post.html.erb, it is best to stick with the local variables that you have passed along, and not rely on the surrounding render context to magically provide variables for you.

Try just changing @comments to comment in the first line of your _comment.html.erb, leave everything else alone, and see if it renders then. Just to be certain, check in the console whether you have any comments for that post you are trying to render. You should not see anything at all (the comment partial won't even render) if post.comments is empty.

Walter

fugee ohu

unread,
Jun 27, 2017, 9:12:46 AM6/27/17
to Ruby on Rails: Talk

I took out the div containers (content_tag_for) and just left:

    <%= simple_format comment.body %>
    <%= comment.post.user.first_name comment.post.user.last_name %>
but I still get the error that comment is undefined

Walter Lee Davis

unread,
Jun 27, 2017, 8:01:40 PM6/27/17
to rubyonra...@googlegroups.com
Where are you calling render on this template? Copy and paste the code here. Also copy and paste the error message so we can compare line numbers from the error with line numbers in your code.

Is the code that is quoted above exactly what you are using in your outer post partial? What should be happening if you call render 'comments/comment', collection: post.comments from inside the post.html.erb partial is that each of the post comments will be rendered one after another, and inside of each of those render calls, the instance variable 'comment' will be loaded with the one comment that is being rendered. This should Just Work™.

Walter

>
> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/eea548b0-8979-4f0c-9662-9c720f5f35db%40googlegroups.com.
Message has been deleted

fugee ohu

unread,
Jun 28, 2017, 1:38:57 AM6/28/17
to Ruby on Rails: Talk


 After some reading it occurred to me explicitly calling the comment partial with <%= render "comments/comment", collection: post.comments %> was defeating the convention for the variable as partial name so I replaced it with <%= render @comments %> and then it worked Of course I had to set @comments=post.comments first on the preceeding line I'd like to know how I could have gotten it working without treating @comments as a standalone resource (in the context of rendering partials) like that

Walter Lee Davis

unread,
Jun 28, 2017, 8:27:57 AM6/28/17
to rubyonra...@googlegroups.com
Ugh. I have seen this before. The reason is that you were calling :

render 'comments/comment'

rather than:

render partial: 'comments/comment'

The former (without the partial keyword) seems to prefer the instance variable, and ignore anything else that you pass to it like collection: post.comments. If I missed that keyword in my examples, I am sorry, that should have been there.

Walter

> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/6011d4f7-4c4b-4477-8e64-313e4f6b0c77%40googlegroups.com.

Jim Ruther Nill

unread,
Jun 28, 2017, 10:53:25 PM6/28/17
to rubyonra...@googlegroups.com
you can get away with just <%= render post.comments %>.  No need to declare the variable.

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe@googlegroups.com.
To post to this group, send email to rubyonrails-talk@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/6011d4f7-4c4b-4477-8e64-313e4f6b0c77%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
-------------------------------------------------------------
visit my blog at http://jimlabs.herokuapp.com

Walter Lee Davis

unread,
Jun 28, 2017, 11:00:55 PM6/28/17
to rubyonra...@googlegroups.com
I would agree, if you were in the comments_controller's context. But since you are in the posts_controller, and the view path is set to views/posts, you will probably get a template not found error when you try to use the shortcut method.

Walter

fugee ohu

unread,
Jun 29, 2017, 10:37:03 AM6/29/17
to Ruby on Rails: Talk

Are there any situations where a partial would have a plural name?

Walter Lee Davis

unread,
Jun 29, 2017, 5:12:37 PM6/29/17
to rubyonra...@googlegroups.com
You can name the partial anything you want, so certainly you could have a partial that you wrote with a plural name. Say if you decided to factor out the comments into a separate file, and you wrote a partial named _comments.html.erb that contained the "long-form" loop over the collection. So if you had taken the first step in factoring out a really deeply nested layout, but not gone all the way down to a single partial rendered multiple times for the individual comments.

But what you have to realize is that if you want to use the shortcut of render @comments, then you do need to have a partial named _comment in the views/comments folder -- that's the only place that Rails will look if it's rendering the comments, and the only way that it will expect you to have structured the application.

The Rails designers have taken a "pave the cowpaths" approach to adding these shortcuts. Time was, you had to pass in the partial keyword and the locals hash and do everything one way only. These additional tricks are taking the "best practices" and making them easier, thus encouraging you to name things a certain way.

Walter

Reply all
Reply to author
Forward
0 new messages