Remote: true with link_to with params - javascript

I have following problem
I have link_to
//_sort_by.html.erb
<%= link_to "sort", :sort_by => "things", remote: true %>
And in my controller I have function which choose posts according to sort_by
def show_posts
#category=Category.find_by(name: params[:sort_by])
if(#category)
#posts=Post.where(category_id: #category)
respond_to do |format|
format.js
format.html
end
else
#posts=Post.all
end
end
and in views
//show_posts.html.erb
<div class="posts">
<%= render #posts %>
</div>
//
and I have _post.html.erb
It works fine (obviously without remote: true), but it refreshes site everytime when I change category of posts so
in show_posts.js.erb I'd like to refresh only class="posts", like
$('.posts').load(location.href + " .posts");
In routes.rb I have get 'show_posts'. But unfortunatelly it doesn't work. Could someone help me?
Edit:
changing show_posts.js.erb to
$('.posts').html("<%= j render #posts %>");
works. Thank you all for tips!

$('.posts').append("<%= escape_javascript render(:partial => 'posts') %>");
Change your show_posts.js.erb with these contents.

Try this out
$('.posts').html("<%= j render 'post' %>");
Hope this helps!

Related

AJAX button processes, doesn't change

I've found a lot of people with the same problem I have, but none of the solutions apply to my situation. I am following Michael Hartl's tutorial here. I have a follow system set up in accordance with chapter 14 (I'm using the latest edition of the book, as I am on Rails 5.1). The follow/unfollow button processes in the database, but I have to manually refresh the page to see the button and follow count change.
I get this in the browser console log:
POST 500 (Internal Server Error)
jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:10255
send # jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:10255
ajax # jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:9739
ajax # jquery_ujs.self-784a997f6726036b1993eb2217c9cb558e1cbb801c6da88105588c56f13b466a.js:94
handleRemote # jquery_ujs.self-784a997f6726036b1993eb2217c9cb558e1cbb801c6da88105588c56f13b466a.js:179
(anonymous) # jquery_ujs.self-784a997f6726036b1993eb2217c9cb558e1cbb801c6da88105588c56f13b466a.js:512
dispatch # jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:5227
elemData.handle # jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:4879
relationships_controller.rb:
class RelationshipsController < ApplicationController
before_action :authenticate_user!
def create
user = User.find(params[:followed_id])
current_user.follow(user)
respond_to do |format|
format.html { redirect_to(:back) }
format.js
end
end
def destroy
user = Relationship.find(params[:id]).followed
current_user.unfollow(user)
respond_to do |format|
format.html { redirect_to(:back) }
format.js
end
end
end
views/users/_follow.html.erb:
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, #user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
views/users/_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: #user.id),
html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn" %>
<% end %>
views/users/_follow_form.html.erb
<% if current_user != #user %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
relationships/create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= #user.followers.count %>');
relationships/destroy.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("#followers").html('<%= #user.followers.count %>');
users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user!, only: [:index, :edit, :update, :destroy,
:following, :followers]
def index
#page_title = "Forge Users"
#users = User.all
end
def show
#user = User.find(params[:id])
#posts = Post.all
end
def following
#title = "Following"
#user = User.find(params[:id])
#users = #user.following
render 'show_follow'
end
def followers
#title = "Followers"
#user = User.find(params[:id])
#users = #user.followers
render 'show_follow'
end
end
What am I doing wrong?
You set local variable user
def create
user = User.find(params[:followed_id])
but reference class instance variable #user in your .js.erb template.
$("#followers").html('<%= #user.followers.count %>');
Instead, set #user = User.find(params[:followed_id]) so it is available to the views. Actually, I think you are trying to set #user = current_user. That might make more sense.
You need to rename your Javascript files to have .erb ending.
relationships/create.js.erb and relationships/destroy.js.erb. It's because you have Ruby in the file so it has to process the Ruby before it gets interpreted as Javascript and sent back.
http://guides.rubyonrails.org/working_with_javascript_in_rails.html#a-simple-example

rails 5 undefine template error

i am creating rails 5 and adding comment to a show action which is displayed in modal
in my show action for comment i have it like this
#selfie = Selfy.find(params[:id])
respond_to do |format|
format.js
end
with this i cant get the show through modal like this
<%= link_to fetch_selfy_path(selfie.id), class: "show_lightbox", data: { featherlight: "mylightbox" }, remote: true do %>
<img class="card-main-image" src="<%= selfie.photo.url if selfie.photo.url %>" alt="Image Alt text">
<% end %>
<div class="lightbox" id="lightbox">
<%=render partial: "selfies/show", locals: { selfie: selfie } %>
</div>
after clicking on the button we show action together with a comment
<% selfie.comments.each do |comment| %>
<%= render partial: "selfies/comments/comment", locals: { comment: comment } %>
<% end %>
where the partial looks like
<p> <b><%= comment.user.username %>: </b><%= comment.body %></p>
all this works fine until i try to inject the new commect through ajax
addCommentToSelfie("<%= j render "selfies/comments/comment", locals: { comment: #comment } %>");
this returns and error of
ActionView::Template::Error (undefined local variable or method `comment' for #<#<Class:0x007f207400c648>:0x00557937265830>):
1:
2: <p> <b><%= comment.user.username %>: </b><%= comment.body %></p>
app/views/selfies/comments/_comment.html.erb:2:in `_app_views_selfies_comments__comment_html_erb__4557429192479440105_46989553619000'
i tried different methond but still getting same error
You're mixing up different syntaxes with some mixing up of quotes too. If you use locals: ... you must also use partial:, or omit both in this case...
addCommentToSelfie("<%= j render 'selfies/comments/comment', comment: #comment %>");
based on the answers provide above, i was able to solve my issue
first i clean my creat.js.erb to
$("#comments").append("<%= j render partial: 'selfies/comments/comment', locals: { comment: #comment } %>");
secondy was getting error nil class because i wasnt using instant variable in my comments controller
from:
def create
comment = #selfie.comments.new(comment_params)
comment.user = current_user
comment.save
end
TO:
def create
#comment = #selfie.comments.new(comment_params)
#comment.user = current_user
#comment.save
respond_to do |format|
format.js
end
from there everything works smoothly
Could you show us the action create in the comment controller ? Usually, I do something like that.
def create
#comment = #selfie.comments.new(comment_params)
#comment.user = current_user
respond_to do |format|
if #comment.save
format.html { redirect_to #comment }
format.js
else
render :new
end
end
end
Then in your view, you should have the file comments/create.js.erb that contains your js :
addCommentToSelfie("<%= j render 'selfies/comments/comment', comment: #comment %>");
And now #comment should exist.

Why does my Rails AJAX delete method only work if I refresh?

I just incorporated the DESTROY method for items in my school project. It worked fine, but now I must use AJAX to complete the action. After implementing this code, it only displays on the browser when I refresh the page, and not instantly when I delete an item. If I did not include enough information please let me know.
_item.html.erb
<% item.each do |i| %>
<p><%= i.name %> | <%= link_to "Complete", i, method: :delete, remote: true, class: 'glyphicon glyphicon-ok' %></p>
<% end %>
destroy.js.erb
<% if #item.destroyed? %>
$('#item-' +<%= #item.id %>).hide();
<% else %>
$('#item-' +<%= #item.id %>).prepend("<%= flash[:error] %>");
<% end %>
items_controller.rb
class ItemsController < ApplicationController
def index
#items = Item.all
end
def show
#item = Item.find(params[:id])
end
def new
#item = Item.new
end
def edit
#item = Item.find(params[:id])
end
def create
#item = Item.new(params.require(:item).permit(:name))
if #item.save
flash[:notice] = "The item was added to your list."
redirect_to current_user
else
flash[:error] = "There was a problem creating your item."
redirect_to current_user
end
end
def destroy
#item = Item.find(params[:id])
if #item.destroy
flash[:notice] = "\"#{#item.name}\" was completed and destroyed."
else
flash[:error] = "There was an error completing the item."
end
respond_to do |format|
format.html
format.js
end
end
end
Flash sets the message for the next request, this is why it works correctly in your create action (because you are redirecting). In your destroy action, you are rendering (which is not good, since it means delete request gets resent on page refresh, you should be redirecting here too) and setting flash, so it shows up on next request (refresh). If you want to send message for the response to the current request, you have to use flash.now :
flash.now[:notice] = "\"#{#item.name}\" was ..."
Again, you should use flash and redirect on success and use flash.now and render on request failure.
EDIT:
The above paragraphs only apply to html requests. I initially missed the point of the question! Thanks BroiSatse
Looking at your display code, you dont seem to be setting the "#item-#item.id", so your return js does nothing. Add it like this:
<p id="item-<%= i.id %>"><%= i.name %> | ...

How can I update an instance variable with each ajax request?

I have a long block of comments on a view of model Page. Instead of showing all the comments on page load, I'm trying to create a "view more" button that shows the next ten comments. The button sends an ajax request to the controller, which then renders this block using jquery:
_view_more.html.erb
<% comments.each_with_index do |comment, index|%>
<% if (( index > #start_number) && (index < #end_number) ) %>
<%= comment.text %>
<% end %>
Let's say I always want to show the next 10 comments. I would just set #start_number = #start_number + 10 and #end_number = #end_number + 10
in the controller, but instance variables get reset, so #start_number would be nil. How can I set a variable that increases by 10 upon every ajax request?
"view more" button
<%= link_to "view more", view_more_page_path, remote: true %>
pages_controller.rb
def view_more
#page = Page.find(params[:id])
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
end
view_more
$("#comments-body").append("<%= escape_javascript(render 'view_more') %>");
I will use haml and coffee-script
When rendering comments you put an html5 data attribute with the id of the comment:
#view where to render comments
%div#comments-wrapper{:"data-pageid" => #page.id}
=render #comments
=link_to "View more", "#", id: "view-more-link"
The comment partial
#comments/_comment.html.haml
%p.single-comment{:"data-commentid" => comment.id}
=comment.body
application.coffee
$ ->
$("#view-more-link").on 'click', ->
last_comment_id = $("#comments-wrapper .single-comment").last().data('commentid')
page_id = $("#comments-wrapper").data("pageid")
$.ajax
url: "/comments/view_more"
dataType: "script"
data:
last_comment_id: last_comment_id
page_id: page_id
comments_controller
def view_more
#page = Page.find(params[:pageid])
if params[:last_comment_id]
#comments = #page.comments.where("comments.id > ?", params[:last_comment_id]).limit(10)
end
respond_to do |format|
format.js
end
end
comments/view_more.js.erb
$("#comments-wrapper").append("<%= escape_javascript(render #comments) %>");
Note: I don't how your routes were set up so I put the page.id as a data-attribute as well
I would use already implemented pagination gems kaminari or will_paginate. I'll create this example using will_paginate.
First of all, it's important to say that your approach is incorrect, because it loads all comments every view_more request. If you want to show 10 comments, makes sense select only they from database, right? The pagination gem will do it for you!
Let's to the code:
"view more" button
<%= link_to "view more", view_more_page_path, remote: true, id: 'view-more-btn' %>
pages_controller.rb
def view_more
#comments = Page.find(params[:id]).comments.paginate(page: params[:page], per_page: 10)
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
end
_view_more.html.erb
<% #comments.each do |comment| %>
<%= comment.text %>
<% end %>
view_more.js.erb
$("#comments-wrapper").append("<%= escape_javascript(render 'view_more') %>");
# We need to update the 'view more' link with the next page number
$('#view-more-btn').attr('href', '<%= view_more_page_path((params[:page] || 0) + 1) %>')
is it not good to update an hidden variable before making ajax call with the count..?
var currentVal = parseInt($("[type=hidden]").val());
$("[type=hidden]").val( currentVal + 1 );
add the hidden field right at the begining of the comments section with default value as "0"
<input type="hidden" name="hiddenId" id="hiddenId" value="0">
Hope it will help
If you want a quick and dirty approach, you could save start_number and end_number inside a cookie.
But keeping track of what needs to be rendered next on client side would be a right thing to do.

Rails: Can I send a GET request to a create path?

I'm trying to append new comments to a list of existing comments using javascript and ajax. I set up my Comments#create to create a new comment and then render its text. But how can I access this text with ajax?
controllers/comments_controller.rb
def new
#comment = Comment.new
#comments = Comment.all
end
def create
#thing = Thing.find(params[:thing_id])
#comment = #thing.comments.create(comment_params)
render text: #comment.text.to_s + "".html_safe
end
My form for a new comment and ajax/javascript attempt:
<%= form_for([#thing, #comment], remote: true) do |f| %>
<%= f.text_area :text, :placeholder => "Explain your rating..." %>
<div id="btn"><%= f.submit "Post", class: "btn", id: "postacomment" %></div>
<script type="text/javascript">
$("#postacomment").click(function() {
$.get( "<%= new_thing_comment_path(:id => #comment.id) %>", function( data ) {
$('#comments_h2').prepend( data );
});
});
</script>
<% end %>
First of all, don't try to bend HTTP methods to fill your needs, follow them instead.
If you want to respond to javascript with rails, that is fairly easy. On your comments controller:
def new
#comment = Comment.new
#comments = Comment.all
end
def create
#thing = Thing.find(params[:thing_id])
#comment = #thing.comments.create(comment_params)
respond_to do |format|
format.html { redirect_to new_comments_path } #this is just a redirection in case JS is disabled
format.js
end
end
As you can see we are now responding to two types of formats, in this case html and js, this forces you to have those corresponding views, or at least for the js version which may look like this:
app/views/comments/create.js.erb:
$('#comments_h2').prepend("<%= j #comment %>");
In the example above I'm assuming you have a partial for rendering a comment, it should look something like:
app/views/comments/_comment.html.erb:
<h2><%= comment.content %></h2>
Obviously you have to update that file to meet your needs.
Hope it helps!

Categories

Resources