*.js.erb files

I wanna render to an element instead of redirecting so went back to my book Agile Web Development with Rails adding ajax it says to make my link remote: true and put a respond_to js in my controller and then use a js.erb file Is that a little dated I’ve been doing some jquery by including *.js files in assets/javascripts Can I render my views to the element using jquery instead of js.erb I notice rails doesn’t generate any js.erb files by default Should I do as the book says or find a way to do it with jquery? thanks ia

There's nothing dated about it. Using RJS (Remote JavaScript) rendering gives you the ability to render just the parts of the page you want to replace. With jQuery, you would still have to render the custom HTML that you want to inject into the page, but then you would use load() or replaceWith() to substitute it into the DOM. Now you have two problems.

Walter

How do i render the form into an element on the page when a user clicks the comment link?

As I iterate through posts I don’t know which post someone’s going to comment but my js.erb file can only render to a class or id name so when i click comment forms are gonna load for all posts on the page What’s the solution please?

There's nothing dated about it. Using RJS (Remote JavaScript) rendering gives you the ability to render just the parts of the page you want to replace. With jQuery, you would still have to render the custom HTML that you want to inject into the page, but then you would use load() or replaceWith() to substitute it into the DOM. Now you have two problems.

Walter

> > I wanna render to an element instead of redirecting so went back to my book Agile Web Development with Rails adding ajax it says to make my link remote: true and put a respond_to js in my controller and then use a js.erb file Is that a little dated I've been doing some jquery by including *.js files in assets/javascripts Can I render my views to the element using jquery instead of js.erb I notice rails doesn't generate any js.erb files by default Should I do as the book says or find a way to do it with jquery? thanks ia > > -- > 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/2a6923a4-e128-4b1f-be14-6eed119e66df%40googlegroups.com. > For more options, visit https://groups.google.com/d/optout.

As I iterate through posts I don't know which post someone's going to comment but my js.erb file can only render to a class or id name so when i click comment forms are gonna load for all posts on the page What's the solution please?

The way I usually do this is I have a partial for a list or table that renders just one of the items, which I gather up in the controller, then I use the content_tag_for() helper (removed from Rails 5, but available in a gem). So my list of items would look like this:

<ul id="items"> <%= render @items %> </ul>

And to get that little bit to work, you just need to have a partial here: app/views/items/_item.html.erb with the following contents:

<%= content_tag_for item, :li do %>   <h1><%= item.title %></h1>   <%= simple_format item.description %> <%- end -%>

In this technique, remember that the local variable (item) inside the partial is named for whatever the partial is named. If you decide to change the name of the partial to item_listing, then inside that partial, your local variable would be item_listing. When you follow the pattern of naming it for the singular of the collection of items you want to render, and you name your collection for the plural, then you can use that lovely terse render @[name of the collection]. But the long form is actually render(partial: 'item', collection: @items), so when you decide to rename the collection or the partial, that's the long-form you need to use in order to clarify what you mean to Rails.

Walter

Your example is with a js file in assets Can we do this with a js.erb in views instead? Same code? What about the file naming convention please Thanks

Actually, it occurred to me after I wrote this that you could do it without any JavaScript at all. In fact, that's what I usually tell people to do first, so I'm surprised I led with the JS example. The thing is, you build the JS version second, as a layer over the HTML version. That way you have a fallback.

In the _item.html.erb partial, you would change the template to include the link helper directly:

<%= content_tag_for item, :li do %>   <h1><%= item.title %></h1>   <%= simple_format item.description %>   <%= link_to 'Comment', new_comment_path(item_id: item.id) %> <%- end -%>

Now that link doesn't have to be "magic'd" into the page with JS at all. It is there and it works. Try it out, see how it works. Then layer JS on top of it (if you want to put the comment form into a modal dialog, for example).

Also, rather than continuing with your current project, I suggest you build a "stunt app" just to work out this linking issue. Just cd up a few levels in your drive, and `rails new stunt-app` and `rails scaffold Item name description:text` and `rails scaffold Comment item:references comment:text` That's enough to work with here, and by using scaffold, you will start with a known-working framework without any assumptions. If you're using Rails 5, don't forget to add the optional: true bit to your belongs_to declaration on Comment. Otherwise you will find that you cannot save an Item without comments.

Now to the naming conventions.

If you use the <%= render @items %> trick, then you have to have a file named views/items/_item.html.erb. Inside that partial, the local variable item will be loaded by the Rails framework if you have passed a collection named @items in your render call. All of that is the optimized "magic" way of doing this. It is a shortcut, and it can be expanded to:

<%= render partial: 'items/item', collection: @items %>

If you name the partial something other than the singular of the collection, then you have to use the long form. If your partial is in a different object's view hierarchy than the one that is rendering it, then you also need to put that part in the partial name (how I used items/item above).

So the same thing could be rendered as:

<%= render partial: 'foos/foo', collection: @items %>

and the partial would be changed to name the instance variable inside it 'foo'.

If you really get into the weeds, then you need to have an iterator in the parent page, and really spell it out for Rails:

<%- @items.each do |item| -%>   <%= render partial: 'items/item', locals: { item: item } %> <%- end -%>

The shortcuts are there to make your production work faster, and if you follow the conventions, then they just work in a way that may confuse you at first. I certainly was confused the first time I did this, particularly when I tried to use a non-conventional setup. It took me a long time for the penny to drop that the name of the instance variable inside the partial was NOT based on the name of the object being rendered, but rather the partial's filename.

Walter

What about the js to render the comment form into the div of the right post id?

> > > > > > > > > > > > There's nothing dated about it. Using RJS (Remote JavaScript) rendering gives you the ability to render just the parts of the page you want to replace. With jQuery, you would still have to render the custom HTML that you want to inject into the page, but then you would use load() or replaceWith() to substitute it into the DOM. Now you have two problems. > > > > Walter > > > > > > > > I wanna render to an element instead of redirecting so went back to my book Agile Web Development with Rails adding ajax it says to make my link remote: true and put a respond_to js in my controller and then use a js.erb file Is that a little dated I've been doing some jquery by including *.js files in assets/javascripts Can I render my views to the element using jquery instead of js.erb I notice rails doesn't generate any js.erb files by default Should I do as the book says or find a way to do it with jquery? thanks ia > > > > > > -- > > > 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/2a6923a4-e128-4b1f-be14-6eed119e66df%40googlegroups.com. > > > For more options, visit https://groups.google.com/d/optout. > > > > > > As I iterate through posts I don't know which post someone's going to comment but my js.erb file can only render to a class or id name so when i click comment forms are gonna load for all posts on the page What's the solution please? > > The way I usually do this is I have a partial for a list or table that renders just one of the items, which I gather up in the controller, then I use the content_tag_for() helper (removed from Rails 5, but available in a gem). So my list of items would look like this: > > <ul id="items"> > <%= render @items %> > </ul> > > And to get that little bit to work, you just need to have a partial here: app/views/items/_item.html.erb with the following contents: > > <%= content_tag_for item, :li do %> > <h1><%= item.title %></h1> > <%= simple_format item.description %> > <%- end -%> > > In this technique, remember that the local variable (item) inside the partial is named for whatever the partial is named. If you decide to change the name of the partial to item_listing, then inside that partial, your local variable would be item_listing. When you follow the pattern of naming it for the singular of the collection of items you want to render, and you name your collection for the plural, then you can use that lovely terse render @[name of the collection]. But the long form is actually render(partial: 'item', collection: @items), so when you decide to rename the collection or the partial, that's the long-form you need to use in order to clarify what you mean to Rails. > > 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/84d6c62f-aa8f-429b-b774-29ccacdd3581%40googlegroups.com. > > For more options, visit https://groups.google.com/d/optout. > > > Your example is with a js file in assets Can we do this with a js.erb in views instead? Same code? What about the file naming convention please Thanks

Actually, it occurred to me after I wrote this that you could do it without any JavaScript at all. In fact, that's what I usually tell people to do first, so I'm surprised I led with the JS example. The thing is, you build the JS version second, as a layer over the HTML version. That way you have a fallback.

In the _item.html.erb partial, you would change the template to include the link helper directly:

<%= content_tag_for item, :li do %>   <h1><%= item.title %></h1>   <%= simple_format item.description %>   <%= link_to 'Comment', new_comment_path(item_id: item.id) %> <%- end -%>

Now that link doesn't have to be "magic'd" into the page with JS at all. It is there and it works. Try it out, see how it works. Then layer JS on top of it (if you want to put the comment form into a modal dialog, for example).

Also, rather than continuing with your current project, I suggest you build a "stunt app" just to work out this linking issue. Just cd up a few levels in your drive, and `rails new stunt-app` and `rails scaffold Item name description:text` and `rails scaffold Comment item:references comment:text` That's enough to work with here, and by using scaffold, you will start with a known-working framework without any assumptions. If you're using Rails 5, don't forget to add the optional: true bit to your belongs_to declaration on Comment. Otherwise you will find that you cannot save an Item without comments.

Now to the naming conventions.

If you use the <%= render @items %> trick, then you have to have a file named views/items/_item.html.erb. Inside that partial, the local variable item will be loaded by the Rails framework if you have passed a collection named @items in your render call. All of that is the optimized "magic" way of doing this. It is a shortcut, and it can be expanded to:

<%= render partial: 'items/item', collection: @items %>

If you name the partial something other than the singular of the collection, then you have to use the long form. If your partial is in a different object's view hierarchy than the one that is rendering it, then you also need to put that part in the partial name (how I used items/item above).

So the same thing could be rendered as:

<%= render partial: 'foos/foo', collection: @items %>

and the partial would be changed to name the instance variable inside it 'foo'.

If you really get into the weeds, then you need to have an iterator in the parent page, and really spell it out for Rails:

<%- @items.each do |item| -%>   <%= render partial: 'items/item', locals: { item: item } %> <%- end -%>

The shortcuts are there to make your production work faster, and if you follow the conventions, then they just work in a way that may confuse you at first. I certainly was confused the first time I did this, particularly when I tried to use a non-conventional setup. It took me a long time for the penny to drop that the name of the instance variable inside the partial was NOT based on the name of the object being rendered, but rather the partial's filename.

Walter

What about the js to render the comment form into the div of the right post id?

Walk first, then run. This code will link to a form, which will load in another page view. Once you have that working, and it can submit, and it can save a comment, then optimize the flow by injecting the form into the page. You will modify the working code, by adding remote: true to the link to the new comment form, and you will add a new.js.erb file to the comments directory, which will inject the form into the parent page. But you cannot do that step before you get the normal new page view form of this working entirely.

Walter

I previously had it working and when you clicked a comment link a new page with a form would load

If you have the form appearing on a new page now, and the form works and can submit and save a comment, then you can change the link to the comment form to include remote: true. Then create a new.js.erb file in the same views folder as your current new.html.erb file.

Use Gist or another pastbin to show me what your _form.html.erb looks like, and what your index.html.erb (specifically your content_tag_for helper) looks like at the moment. That will determine what we put into the new.js.erb file.

Walter

I have <%= render post.comments %> in _post.html.erb This doesn’t use the view app/views/comments/_comment.html.erb I don’t know what view it calls, it doesn’t seem to call any partial view at all … ?

I can’t figure out what variables from _post.html.erb will be available to _comment.html.erb Also, do I need the index action in the comments_controller.rb and an index view Maybe I need it to chain the two partials together Here they are https://gist.github.com/mices/d9aa8b344c214c4a422ffc8a538eb566

> > I previously had it working and when you clicked a comment link a new page with a form would load > >

If you have the form appearing on a new page now, and the form works and can submit and save a comment, then you can change the link to the comment form to include remote: true. Then create a new.js.erb file in the same views folder as your current new.html.erb file.

Use Gist or another pastbin to show me what your _form.html.erb looks like, and what your index.html.erb (specifically your content_tag_for helper) looks like at the moment. That will determine what we put into the new.js.erb file.

Walter

I can't figure out what variables from _post.html.erb will be available to _comment.html.erb Also, do I need the index action in the comments_controller.rb and an index view Maybe I need it to chain the two partials together Here they are https://gist.github.com/mices/d9aa8b344c214c4a422ffc8a538eb566

There's a few fundamental flaws here. You have the link to create a new comment inside the comment partial, not the post partial. The post needs to be the holder of this link, because there is only supposed to be one link per post that reads "Add a comment". Also, your link_to is missing the first argument -- there's no link text being supplied -- so I'm surprised if this template even compiles and displays.

You're also missing the surrounding HTML that I suggested to you when you asked how to get this into the "Ajax" format. Without those surrounding content_tag_for wrappers, the return from Rails has no idea where to insert the form or the updated comments. What I believe you need to end up with is something that looks like this (in _post.html.erb):

content_tag_for :div, post, 'comments' do

  content_tag_for :div, post, 'comment_form_holder' do     link_to 'Add a Comment', new_comment_path(commentable_id: post.id, commentable_type: 'Post'), remote: true   end

  render 'comments/comment', collection: post.comments

end

So what you should get is a structure like this:

<div id="post_comments_123">   <div id="post_comment_form_holder_123">     <a href="/comments/new?commentable_id=123&commentable_type=Post" data-remote="true">Add a Comment</a>   </div>   <div id="post_comment_345">     Hello, this is a comment   </div> </div>

When someone clicks the Add a Comment link, because it is set to remote: true, the comments/new.js.erb template will render (by default), and as we discussed earlier, that template is set to update the appropriate container (post_comment_form_holder_123) with the new comment form contents. So the action is you click the link, and the link disappears, replaced by the form to add a comment.

Walter

There’s only one list of comments per post so why can’t the link for a new comment be in the comments partial In any resource the index view has a link to new, from the folder for that resource … i dunno, are you sure it has to be in the post folder/containers?

The link is in the _comment partial (singular). There is no _comments (plural) partial. If there was, then you could put the link there. But here's the thing. A post has_many comments. Until the first one is put in, you will see zero comments, and thus (if you put the link in the _comment (singular) partial, there won't be any link, because the _comment partial will be rendered zero times.

But further, if you put it where you did, you have some more problems. You will have a new link below each comment. Unless you are planning to allow comments on comments (some sort of threaded nesting structure), then this will look awful and make no sense. So if you are somehow able to render the first comment, the second one will get its own Add Comment link. Beyond that, in order to inject the form into the page the way you want to, you need to insert the form into some identifiable DOM object, which you didn't provide in your sample templates.

Please try what I suggest -- I've been doing this for a large number of years, sometimes badly and without understanding, and I'd like to see the penny drop for you. I promise it can make sense once you stop pushing so hard to go a different way.

Walter

You may want to read this step-by-step I wrote for a lunch-n-learn at Penn: refactoring_to_partials.md · GitHub

It covers starting with a fully inline layout, and moving into partials. Funny enough, it features articles and comments.

Walter

Thanks Walter Just to add, the additional options in div_for or content_tag_for are pre-pended “comment_post_345” , “comment_form_holder_post_123”